am aabf3b45: Explicitly set DataLayout for 32-bit.

* commit 'aabf3b45a05d80949fdb0551feb1f59754f3742a':
  Explicitly set DataLayout for 32-bit.
diff --git a/Android.mk b/Android.mk
index ee0f7a4..c1745a8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,7 +19,8 @@
 ifeq ($(TARGET_BUILD_APPS),)
 
 
-local_cflags_for_slang := -Wno-sign-promo -Wall -Wno-unused-parameter -Wno-return-type -Werror
+local_cflags_for_slang := -Wno-sign-promo -Wall -Wno-unused-parameter \
+                          -Wno-return-type -Werror -std=c++11
 ifeq ($(TARGET_BUILD_VARIANT),eng)
 local_cflags_for_slang += -O0
 else
@@ -69,7 +70,6 @@
 
 LOCAL_SRC_FILES :=	\
 	slang.cpp	\
-	slang_utils.cpp	\
 	slang_backend.cpp	\
 	slang_pragma_recorder.cpp	\
 	slang_diagnostic_buffer.cpp
@@ -78,7 +78,7 @@
 
 LOCAL_LDLIBS := -ldl -lpthread
 ifneq ($(HOST_OS),windows)
-LOCAL_LDLIBS += -lc++
+LOCAL_CXX_STL := libc++
 endif
 
 include $(CLANG_HOST_BUILD_MK)
@@ -157,6 +157,8 @@
 	slang_rs_reflect_utils.cpp \
 	strip_unknown_attributes.cpp
 
+LOCAL_C_INCLUDES += frameworks/compile/libbcc/include
+
 LOCAL_STATIC_LIBRARIES :=	\
 	libslang \
 	$(static_libraries_needed_by_slang)
diff --git a/llvm-rs-as.cpp b/llvm-rs-as.cpp
index b176002..1f81b14 100644
--- a/llvm-rs-as.cpp
+++ b/llvm-rs-as.cpp
@@ -87,12 +87,12 @@
     }
   }
 
-  std::string ErrorInfo;
+  std::error_code EC;
   std::unique_ptr<tool_output_file> Out
-  (new tool_output_file(OutputFilename.c_str(), ErrorInfo,
-                        llvm::sys::fs::F_None));
-  if (!ErrorInfo.empty()) {
-    errs() << ErrorInfo << '\n';
+  (new tool_output_file(OutputFilename.c_str(), EC, llvm::sys::fs::F_None));
+  if (EC) {
+    // TODO(srhines): This isn't actually very specific and needs cleanup.
+    errs() << EC.message() << '\n';
     exit(1);
   }
 
@@ -127,7 +127,7 @@
 
   // Parse the file now...
   SMDiagnostic Err;
-  std::unique_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context));
+  std::unique_ptr<Module> M(parseAssemblyFile(InputFilename, Err, Context));
   if (M.get() == 0) {
     Err.print(argv[0], errs());
     return 1;
diff --git a/rs_version.mk b/rs_version.mk
index 909496a..d824bcc 100644
--- a/rs_version.mk
+++ b/rs_version.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-RS_VERSION := 22
+RS_VERSION := 23
 RS_VERSION_DEFINE := -DRS_VERSION=$(RS_VERSION)
 
 # Use RS_VERSION_DEFINE as part of your LOCAL_CFLAGS to have the proper value.
diff --git a/slang.cpp b/slang.cpp
index 039b17a..731e671 100644
--- a/slang.cpp
+++ b/slang.cpp
@@ -68,32 +68,12 @@
 
 #include "slang_assert.h"
 #include "slang_backend.h"
-#include "slang_utils.h"
 
 namespace {
 
 static const char *kRSTriple32 = "armv7-none-linux-gnueabi";
 static const char *kRSTriple64 = "aarch64-none-linux-gnueabi";
 
-struct ForceSlangLinking {
-  ForceSlangLinking() {
-    // We must reference the functions in such a way that compilers will not
-    // delete it all as dead code, even with whole program optimization,
-    // yet is effectively a NO-OP. As the compiler isn't smart enough
-    // to know that getenv() never returns -1, this will do the job.
-    if (std::getenv("bar") != reinterpret_cast<char*>(-1))
-      return;
-
-    // llvm-rs-link needs following functions existing in libslang.
-    llvm::parseBitcodeFile(NULL, llvm::getGlobalContext());
-    llvm::Linker::LinkModules(NULL, NULL, 0, NULL);
-
-    // llvm-rs-cc need this.
-    new clang::TextDiagnosticPrinter(llvm::errs(),
-                                     new clang::DiagnosticOptions());
-  }
-} ForceSlangLinking;
-
 }  // namespace
 
 namespace slang {
@@ -113,40 +93,34 @@
 static inline llvm::tool_output_file *
 OpenOutputFile(const char *OutputFile,
                llvm::sys::fs::OpenFlags Flags,
-               std::string* Error,
+               std::error_code &EC,
                clang::DiagnosticsEngine *DiagEngine) {
-  slangAssert((OutputFile != NULL) && (Error != NULL) &&
-              (DiagEngine != NULL) && "Invalid parameter!");
+  slangAssert((OutputFile != nullptr) &&
+              (DiagEngine != nullptr) && "Invalid parameter!");
 
-  if (SlangUtils::CreateDirectoryWithParents(
-                        llvm::sys::path::parent_path(OutputFile), Error)) {
+  EC = llvm::sys::fs::create_directories(
+      llvm::sys::path::parent_path(OutputFile));
+  if (!EC) {
     llvm::tool_output_file *F =
-          new llvm::tool_output_file(OutputFile, *Error, Flags);
-    if (F != NULL)
+          new llvm::tool_output_file(OutputFile, EC, Flags);
+    if (F != nullptr)
       return F;
   }
 
   // Report error here.
   DiagEngine->Report(clang::diag::err_fe_error_opening)
-    << OutputFile << *Error;
+    << OutputFile << EC.message();
 
-  return NULL;
+  return nullptr;
 }
 
 void Slang::GlobalInitialization() {
   if (!GlobalInitialized) {
-    // We only support x86, x64 and ARM target
 
-    // For ARM
     LLVMInitializeARMTargetInfo();
     LLVMInitializeARMTarget();
     LLVMInitializeARMAsmPrinter();
 
-    // For x86 and x64
-    LLVMInitializeX86TargetInfo();
-    LLVMInitializeX86Target();
-    LLVMInitializeX86AsmPrinter();
-
     // Please refer to include/clang/Basic/LangOptions.h to setup
     // the options.
     LangOpts.RTTI = 0;  // Turn off the RTTI information support
@@ -213,7 +187,7 @@
                                     *mSourceMgr,
                                     *HeaderInfo,
                                     *this,
-                                    NULL,
+                                    nullptr,
                                     /* OwnsHeaderSearch = */true));
   // Initialize the preprocessor
   mPP->Initialize(getTargetInfo());
@@ -258,7 +232,7 @@
                      &mPragmas, OS, OT);
 }
 
-Slang::Slang() : mInitialized(false), mDiagClient(NULL),
+Slang::Slang() : mInitialized(false), mDiagClient(nullptr),
   mTargetOpts(new clang::TargetOptions()), mOT(OT_Default) {
   GlobalInitialization();
 }
@@ -299,9 +273,9 @@
   mSourceMgr->clearIDTables();
 
   // Load the source
-  llvm::MemoryBuffer *SB =
+  std::unique_ptr<llvm::MemoryBuffer> SB =
       llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength);
-  mSourceMgr->setMainFileID(mSourceMgr->createFileID(SB));
+  mSourceMgr->setMainFileID(mSourceMgr->createFileID(std::move(SB)));
 
   if (mSourceMgr->getMainFileID().isInvalid()) {
     mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile;
@@ -330,15 +304,14 @@
 }
 
 bool Slang::setOutput(const char *OutputFile) {
-  std::string Error;
-  llvm::tool_output_file *OS = NULL;
+  std::error_code EC;
+  llvm::tool_output_file *OS = nullptr;
 
   switch (mOT) {
     case OT_Dependency:
     case OT_Assembly:
     case OT_LLVMAssembly: {
-      OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, &Error,
-          mDiagEngine);
+      OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, EC, mDiagEngine);
       break;
     }
     case OT_Nothing: {
@@ -346,8 +319,7 @@
     }
     case OT_Object:
     case OT_Bitcode: {
-      OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_None,
-                          &Error, mDiagEngine);
+      OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_None, EC, mDiagEngine);
       break;
     }
     default: {
@@ -355,7 +327,7 @@
     }
   }
 
-  if (!Error.empty())
+  if (EC)
     return false;
 
   mOS.reset(OS);
@@ -366,11 +338,11 @@
 }
 
 bool Slang::setDepOutput(const char *OutputFile) {
-  std::string Error;
+  std::error_code EC;
 
   mDOS.reset(
-      OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, &Error, mDiagEngine));
-  if (!Error.empty() || (mDOS.get() == NULL))
+      OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, EC, mDiagEngine));
+  if (EC || (mDOS.get() == nullptr))
     return false;
 
   mDepOutputFileName = OutputFile;
@@ -381,7 +353,7 @@
 int Slang::generateDepFile() {
   if (mDiagEngine->hasErrorOccurred())
     return 1;
-  if (mDOS.get() == NULL)
+  if (mDOS.get() == nullptr)
     return 1;
 
   // Initialize options for generating dependency file
@@ -428,7 +400,7 @@
 int Slang::compile() {
   if (mDiagEngine->hasErrorOccurred())
     return 1;
-  if (mOS.get() == NULL)
+  if (mOS.get() == nullptr)
     return 1;
 
   // Here is per-compilation needed initialization
@@ -481,6 +453,10 @@
   }
   mDiagEngine->Reset();
   mDiagClient->reset();
+
+  // remove fatal error handler.  slang::init needs to be called before another
+  // compilation, which will re-install the error handler.
+  llvm::remove_fatal_error_handler();
 }
 
 Slang::~Slang() {
diff --git a/slang_backend.cpp b/slang_backend.cpp
index 43d843e..4c6a3b9 100644
--- a/slang_backend.cpp
+++ b/slang_backend.cpp
@@ -65,7 +65,7 @@
 void Backend::CreateFunctionPasses() {
   if (!mPerFunctionPasses) {
     mPerFunctionPasses = new llvm::FunctionPassManager(mpModule);
-    mPerFunctionPasses->add(new llvm::DataLayoutPass(mpModule));
+    mPerFunctionPasses->add(new llvm::DataLayoutPass());
 
     llvm::PassManagerBuilder PMBuilder;
     PMBuilder.OptLevel = mCodeGenOpts.OptimizationLevel;
@@ -76,7 +76,7 @@
 void Backend::CreateModulePasses() {
   if (!mPerModulePasses) {
     mPerModulePasses = new llvm::PassManager();
-    mPerModulePasses->add(new llvm::DataLayoutPass(mpModule));
+    mPerModulePasses->add(new llvm::DataLayoutPass());
 
     llvm::PassManagerBuilder PMBuilder;
     PMBuilder.OptLevel = mCodeGenOpts.OptimizationLevel;
@@ -108,7 +108,7 @@
     return true;
   } else {
     mCodeGenPasses = new llvm::FunctionPassManager(mpModule);
-    mCodeGenPasses->add(new llvm::DataLayoutPass(mpModule));
+    mCodeGenPasses->add(new llvm::DataLayoutPass());
   }
 
   // Create the TargetMachine for generating code.
@@ -117,7 +117,7 @@
   std::string Error;
   const llvm::Target* TargetInfo =
       llvm::TargetRegistry::lookupTarget(Triple, Error);
-  if (TargetInfo == NULL) {
+  if (TargetInfo == nullptr) {
     mDiagEngine.Report(clang::diag::err_fe_unable_to_create_target) << Error;
     return false;
   }
@@ -209,13 +209,13 @@
                  Slang::OutputType OT)
     : ASTConsumer(),
       mTargetOpts(TargetOpts),
-      mpModule(NULL),
+      mpModule(nullptr),
       mpOS(OS),
       mOT(OT),
-      mGen(NULL),
-      mPerFunctionPasses(NULL),
-      mPerModulePasses(NULL),
-      mCodeGenPasses(NULL),
+      mGen(nullptr),
+      mPerFunctionPasses(nullptr),
+      mPerModulePasses(nullptr),
+      mCodeGenPasses(nullptr),
       mLLVMContext(llvm::getGlobalContext()),
       mDiagEngine(*DiagEngine),
       mCodeGenOpts(CodeGenOpts),
@@ -268,7 +268,7 @@
   llvm::Module *M = mGen->ReleaseModule();
   if (!M) {
     // The module has been released by IR gen on failures, do not double free.
-    mpModule = NULL;
+    mpModule = nullptr;
     return;
   }
 
diff --git a/slang_rs.cpp b/slang_rs.cpp
index c59459b..88eb909 100644
--- a/slang_rs.cpp
+++ b/slang_rs.cpp
@@ -180,11 +180,14 @@
 
 void SlangRS::initDiagnostic() {
   clang::DiagnosticsEngine &DiagEngine = getDiagnostics();
+  const auto Flavor = clang::diag::Flavor::WarningOrError;
 
-  if (DiagEngine.setSeverityForGroup("implicit-function-declaration",
-                                     clang::diag::Severity::Error))
-    DiagEngine.Report(clang::diag::warn_unknown_warning_option)
+  if (DiagEngine.setSeverityForGroup(Flavor, "implicit-function-declaration",
+                                     clang::diag::Severity::Error)) {
+    DiagEngine.Report(clang::diag::warn_unknown_diag_option)
+      << /* clang::diag::Flavor::WarningOrError */ 0
       << "implicit-function-declaration";
+  }
 
   DiagEngine.setSeverity(
     clang::diag::ext_typecheck_convert_discards_qualifiers,
@@ -266,7 +269,7 @@
 }
 
 SlangRS::SlangRS()
-  : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0),
+  : Slang(), mRSContext(nullptr), mAllowRSPrefix(false), mTargetAPI(0),
     mVerbose(false), mIsFilterscript(false) {
 }
 
@@ -440,7 +443,7 @@
 
 void SlangRS::reset(bool SuppressWarnings) {
   delete mRSContext;
-  mRSContext = NULL;
+  mRSContext = nullptr;
   mGeneratedFileNames.clear();
   Slang::reset(SuppressWarnings);
 }
diff --git a/slang_rs_ast_replace.h b/slang_rs_ast_replace.h
index 0507603..f93171d 100644
--- a/slang_rs_ast_replace.h
+++ b/slang_rs_ast_replace.h
@@ -58,11 +58,11 @@
  public:
   explicit RSASTReplace(clang::ASTContext &Con)
       : C(Con),
-        mOuterStmt(NULL),
-        mOldStmt(NULL),
-        mNewStmt(NULL),
-        mOldExpr(NULL),
-        mNewExpr(NULL) {
+        mOuterStmt(nullptr),
+        mOldStmt(nullptr),
+        mNewStmt(nullptr),
+        mOldExpr(nullptr),
+        mNewExpr(nullptr) {
   }
 
   void VisitStmt(clang::Stmt *S);
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index 5d92a12..4d1998e 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -61,12 +61,12 @@
     mSourceMgr(SourceMgr),
     mAllowRSPrefix(AllowRSPrefix),
     mIsFilterscript(IsFilterscript),
-    mExportVarMetadata(NULL),
-    mExportFuncMetadata(NULL),
-    mExportForEachNameMetadata(NULL),
-    mExportForEachSignatureMetadata(NULL),
-    mExportTypeMetadata(NULL),
-    mRSObjectSlotsMetadata(NULL),
+    mExportVarMetadata(nullptr),
+    mExportFuncMetadata(nullptr),
+    mExportForEachNameMetadata(nullptr),
+    mExportForEachSignatureMetadata(nullptr),
+    mExportTypeMetadata(nullptr),
+    mRSObjectSlotsMetadata(nullptr),
     mRefCount(mContext->getASTContext()),
     mASTChecker(Context, Context->getTargetAPI(), IsFilterscript) {
 }
@@ -88,7 +88,7 @@
     for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end();
          I != E; I++) {
       clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
-      if (FD == NULL)
+      if (FD == nullptr)
         continue;
       if (!FD->getName().startswith("rs"))  // Check prefix
         continue;
@@ -182,7 +182,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 void RSBackend::dumpExportVarInfo(llvm::Module *M) {
   int slotCount = 0;
-  if (mExportVarMetadata == NULL)
+  if (mExportVarMetadata == nullptr)
     mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
 
   llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
@@ -251,7 +251,7 @@
         llvm::MDNode::get(mLLVMContext, ExportVarInfo));
     ExportVarInfo.clear();
 
-    if (mRSObjectSlotsMetadata == NULL) {
+    if (mRSObjectSlotsMetadata == nullptr) {
       mRSObjectSlotsMetadata =
           M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
     }
@@ -266,7 +266,7 @@
 }
 
 void RSBackend::dumpExportFunctionInfo(llvm::Module *M) {
-  if (mExportFuncMetadata == NULL)
+  if (mExportFuncMetadata == nullptr)
     mExportFuncMetadata =
         M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
 
@@ -292,8 +292,9 @@
 
       // Create helper function
       {
-        llvm::StructType *HelperFunctionParameterTy = NULL;
+        llvm::StructType *HelperFunctionParameterTy = nullptr;
         std::vector<bool> isStructInput;
+
         if (!F->getArgumentList().empty()) {
           std::vector<llvm::Type*> HelperFunctionParameterTys;
           for (llvm::Function::arg_iterator AI = F->arg_begin(),
@@ -405,11 +406,11 @@
 }
 
 void RSBackend::dumpExportForEachInfo(llvm::Module *M) {
-  if (mExportForEachNameMetadata == NULL) {
+  if (mExportForEachNameMetadata == nullptr) {
     mExportForEachNameMetadata =
         M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
   }
-  if (mExportForEachSignatureMetadata == NULL) {
+  if (mExportForEachSignatureMetadata == nullptr) {
     mExportForEachSignatureMetadata =
         M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
   }
@@ -461,7 +462,7 @@
       const RSExportRecordType *ERT =
           static_cast<const RSExportRecordType*>(ET);
 
-      if (mExportTypeMetadata == NULL)
+      if (mExportTypeMetadata == nullptr)
         mExportTypeMetadata =
             M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
 
diff --git a/slang_rs_check_ast.cpp b/slang_rs_check_ast.cpp
index b5cb024..848a176 100644
--- a/slang_rs_check_ast.cpp
+++ b/slang_rs_check_ast.cpp
@@ -260,7 +260,7 @@
   E = E->IgnoreImpCasts();
   if (mIsFilterscript &&
       !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
-      !RSExportType::ValidateType(Context, C, E->getType(), NULL, E->getExprLoc(),
+      !RSExportType::ValidateType(Context, C, E->getType(), nullptr, E->getExprLoc(),
                                   mTargetAPI, mIsFilterscript)) {
     mValid = false;
   } else {
diff --git a/slang_rs_context.cpp b/slang_rs_context.cpp
index bef4766..608d6cb 100644
--- a/slang_rs_context.cpp
+++ b/slang_rs_context.cpp
@@ -53,9 +53,9 @@
       mPragmas(Pragmas),
       mTargetAPI(TargetAPI),
       mVerbose(Verbose),
-      mDataLayout(NULL),
+      mDataLayout(nullptr),
       mLLVMContext(llvm::getGlobalContext()),
-      mLicenseNote(NULL),
+      mLicenseNote(nullptr),
       mRSPackageName("android.renderscript"),
       version(0),
       mMangleCtx(Ctx.createMangleContext()),
@@ -77,7 +77,7 @@
     return false;
 
   RSExportVar *EV = new RSExportVar(this, VD, ET);
-  if (EV == NULL)
+  if (EV == nullptr)
     return false;
   else
     mExportVars.push_back(EV);
@@ -103,7 +103,7 @@
     return RSExportForEach::validateSpecialFuncDecl(mTargetAPI, this, FD);
   } else if (RSExportForEach::isRSForEachFunc(mTargetAPI, this, FD)) {
     RSExportForEach *EFE = RSExportForEach::Create(this, FD);
-    if (EFE == NULL)
+    if (EFE == nullptr)
       return false;
     else
       mExportForEach.push_back(EFE);
@@ -111,7 +111,7 @@
   }
 
   RSExportFunc *EF = RSExportFunc::Create(this, FD);
-  if (EF == NULL)
+  if (EF == nullptr)
     return false;
   else
     mExportFuncs.push_back(EF);
@@ -123,23 +123,23 @@
 bool RSContext::processExportType(const llvm::StringRef &Name) {
   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
 
-  slangAssert(TUDecl != NULL && "Translation unit declaration (top-level "
-                                "declaration) is null object");
+  slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level "
+                                   "declaration) is null object");
 
   const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
-  if (II == NULL)
+  if (II == nullptr)
     // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
     //             found
     return false;
 
   clang::DeclContext::lookup_const_result R = TUDecl->lookup(II);
-  RSExportType *ET = NULL;
+  RSExportType *ET = nullptr;
 
   for (clang::DeclContext::lookup_const_iterator I = R.begin(), E = R.end();
        I != E;
        I++) {
     clang::NamedDecl *const ND = *I;
-    const clang::Type *T = NULL;
+    const clang::Type *T = nullptr;
 
     switch (ND->getKind()) {
       case clang::Decl::Typedef: {
@@ -157,11 +157,11 @@
       }
     }
 
-    if (T != NULL)
+    if (T != nullptr)
       ET = RSExportType::Create(this, T);
   }
 
-  return (ET != NULL);
+  return (ET != nullptr);
 }
 
 
diff --git a/slang_rs_context.h b/slang_rs_context.h
index c47f4c1..8e9b577 100644
--- a/slang_rs_context.h
+++ b/slang_rs_context.h
@@ -158,7 +158,7 @@
 
   bool processExport();
   inline void newExportable(RSExportable *E) {
-    if (E != NULL)
+    if (E != nullptr)
       mExportables.push_back(E);
   }
   typedef ExportableList::iterator exportable_iterator;
diff --git a/slang_rs_export_element.cpp b/slang_rs_export_element.cpp
index 00d5a53..a5985bb 100644
--- a/slang_rs_export_element.cpp
+++ b/slang_rs_export_element.cpp
@@ -74,15 +74,15 @@
   // Create RSExportType corresponded to the @T first and then verify
 
   llvm::StringRef TypeName;
-  RSExportType *ET = NULL;
+  RSExportType *ET = nullptr;
 
   if (!Initialized)
     Init();
 
-  slangAssert(EI != NULL && "Element info not found");
+  slangAssert(EI != nullptr && "Element info not found");
 
-  if (!RSExportType::NormalizeType(T, TypeName, Context, NULL))
-    return NULL;
+  if (!RSExportType::NormalizeType(T, TypeName, Context, nullptr))
+    return nullptr;
 
   switch (T->getTypeClass()) {
     case clang::Type::Builtin:
@@ -131,7 +131,7 @@
                                               const clang::DeclaratorDecl *DD) {
   const clang::Type* T = RSExportType::GetTypeOfDecl(DD);
   const clang::Type* CT = GetCanonicalType(T);
-  const ElementInfo* EI = NULL;
+  const ElementInfo* EI = nullptr;
 
   // Note: RS element like rs_pixel_rgb elements are either in the type of
   // primitive or vector.
@@ -149,14 +149,14 @@
       const clang::TypedefType *TT = static_cast<const clang::TypedefType*>(T);
       const clang::TypedefNameDecl *TD = TT->getDecl();
       EI = GetElementInfo(TD->getName());
-      if (EI != NULL)
+      if (EI != nullptr)
         break;
 
       T = TD->getUnderlyingType().getTypePtr();
     }
   }
 
-  if (EI == NULL) {
+  if (EI == nullptr) {
     return RSExportType::Create(Context, T);
   } else {
     return RSExportElement::Create(Context, T, EI);
@@ -170,7 +170,7 @@
 
   ElementInfoMapTy::const_iterator I = ElementInfoMap.find(Name);
   if (I == ElementInfoMap.end())
-    return NULL;
+    return nullptr;
   else
     return I->getValue();
 }
diff --git a/slang_rs_export_foreach.cpp b/slang_rs_export_foreach.cpp
index 439f9a9..d3ba154 100644
--- a/slang_rs_export_foreach.cpp
+++ b/slang_rs_export_foreach.cpp
@@ -25,11 +25,69 @@
 
 #include "llvm/IR/DerivedTypes.h"
 
+#include "bcinfo/MetadataExtractor.h"
+
 #include "slang_assert.h"
 #include "slang_rs_context.h"
 #include "slang_rs_export_type.h"
 #include "slang_version.h"
 
+namespace {
+
+const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
+
+enum SpecialParameterKind {
+  SPK_INT,  // 'int' or 'unsigned int'
+  SPK_CTXT, // rs_kernel_context
+};
+
+struct SpecialParameter {
+  const char *name;
+  bcinfo::MetadataSignatureBitval bitval;
+  SpecialParameterKind kind;
+  SlangTargetAPI minAPI;
+};
+
+// Table entries are in the order parameters must occur in a kernel parameter list.
+const SpecialParameter specialParameterTable[] = {
+  { "ctxt", bcinfo::MD_SIG_Ctxt, SPK_CTXT, SLANG_23_TARGET_API },
+  { "x", bcinfo::MD_SIG_X, SPK_INT, SLANG_MINIMUM_TARGET_API },
+  { "y", bcinfo::MD_SIG_Y, SPK_INT, SLANG_MINIMUM_TARGET_API },
+  { "z", bcinfo::MD_SIG_Z, SPK_INT, SLANG_23_TARGET_API },
+  { nullptr, bcinfo::MD_SIG_None, SPK_INT, SLANG_MINIMUM_TARGET_API }, // marks end of table
+};
+
+// If the specified name matches the name of an entry in
+// specialParameterTable, return the corresponding table index;
+// otherwise return -1.
+int lookupSpecialParameter(const llvm::StringRef name) {
+  for (int i = 0; specialParameterTable[i].name != nullptr; ++i)
+    if (name.equals(specialParameterTable[i].name))
+      return i;
+  return -1;
+}
+
+// Return a comma-separated list of names in specialParameterTable
+// that are available at the specified API level.
+std::string listSpecialParameters(unsigned int api) {
+  std::string ret;
+  bool first = true;
+  for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
+    if (specialParameterTable[i].minAPI > api)
+      continue;
+    if (first)
+      first = false;
+    else
+      ret += ", ";
+    ret += "'";
+    ret += specialParameterTable[i].name;
+    ret += "'";
+  }
+  return ret;
+}
+
+}
+
 namespace slang {
 
 // This function takes care of additional validation and construction of
@@ -85,30 +143,30 @@
   }
 
   // Validate remaining parameter types
-  // TODO(all): Add support for LOD/face when we have them
 
-  size_t IndexOfFirstIterator = numParams;
-  valid |= validateIterationParameters(Context, FD, &IndexOfFirstIterator);
+  size_t IndexOfFirstSpecialParameter = numParams;
+  valid |= validateSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
 
-  // Validate the non-iterator parameters, which should all be found before the
-  // first iterator.
-  for (size_t i = 0; i < IndexOfFirstIterator; i++) {
+  // Validate the non-special parameters, which should all be found before the
+  // first special parameter.
+  for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
     const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
     clang::QualType QT = PVD->getType().getCanonicalType();
 
     if (!QT->isPointerType()) {
       Context->ReportError(PVD->getLocation(),
                            "Compute kernel %0() cannot have non-pointer "
-                           "parameters besides 'x' and 'y'. Parameter '%1' is "
-                           "of type: '%2'")
-          << FD->getName() << PVD->getName() << PVD->getType().getAsString();
+                           "parameters besides (%1). Parameter '%2' is "
+                           "of type: '%3'")
+          << FD->getName() << listSpecialParameters(Context->getTargetAPI())
+          << PVD->getName() << PVD->getType().getAsString();
       valid = false;
       continue;
     }
 
     // The only non-const pointer should be out.
     if (!QT->getPointeeType().isConstQualified()) {
-      if (mOut == NULL) {
+      if (mOut == nullptr) {
         mOut = PVD;
       } else {
         Context->ReportError(PVD->getLocation(),
@@ -119,9 +177,9 @@
         valid = false;
       }
     } else {
-      if (mIns.empty() && mOut == NULL) {
+      if (mIns.empty() && mOut == nullptr) {
         mIns.push_back(PVD);
-      } else if (mUsrData == NULL) {
+      } else if (mUsrData == nullptr) {
         mUsrData = PVD;
       } else {
         Context->ReportError(
@@ -173,14 +231,13 @@
   }
 
   // Validate remaining parameter types
-  // TODO(all): Add support for LOD/face when we have them
 
-  size_t IndexOfFirstIterator = numParams;
-  valid |= validateIterationParameters(Context, FD, &IndexOfFirstIterator);
+  size_t IndexOfFirstSpecialParameter = numParams;
+  valid |= validateSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
 
-  // Validate the non-iterator parameters, which should all be found before the
-  // first iterator.
-  for (size_t i = 0; i < IndexOfFirstIterator; i++) {
+  // Validate the non-special parameters, which should all be found before the
+  // first special.
+  for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
     const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
 
     /*
@@ -188,7 +245,17 @@
      *        multi-input feature is officially supported.
      */
     if (Context->getTargetAPI() == SLANG_DEVELOPMENT_TARGET_API || i == 0) {
-      mIns.push_back(PVD);
+      if (i >= RS_KERNEL_INPUT_LIMIT) {
+        Context->ReportError(PVD->getLocation(),
+                             "Invalid parameter '%0' for compute kernel %1(). "
+                             "Kernels targeting SDK levels %2-%3 may not use "
+                             "more than %4 input parameters.") << PVD->getName() <<
+                             FD->getName() << SLANG_MINIMUM_TARGET_API <<
+                             SLANG_MAXIMUM_TARGET_API << int(RS_KERNEL_INPUT_LIMIT);
+
+      } else {
+        mIns.push_back(PVD);
+      }
     } else {
       Context->ReportError(PVD->getLocation(),
                            "Invalid parameter '%0' for compute kernel %1(). "
@@ -221,73 +288,119 @@
   return valid;
 }
 
-// Search for the optional x and y parameters.  Returns true if valid.   Also
-// sets *IndexOfFirstIterator to the index of the first iterator parameter, or
+// Search for the optional special parameters.  Returns true if valid.   Also
+// sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or
 // FD->getNumParams() if none are found.
-bool RSExportForEach::validateIterationParameters(
+bool RSExportForEach::validateSpecialParameters(
     RSContext *Context, const clang::FunctionDecl *FD,
-    size_t *IndexOfFirstIterator) {
-  slangAssert(IndexOfFirstIterator != NULL);
-  slangAssert(mX == NULL && mY == NULL);
+    size_t *IndexOfFirstSpecialParameter) {
+  slangAssert(IndexOfFirstSpecialParameter != nullptr);
+  slangAssert(mSpecialParameterSignatureMetadata == 0);
   clang::ASTContext &C = Context->getASTContext();
 
-  // Find the x and y parameters if present.
+  // Find all special parameters if present.
+  int LastSpecialParameterIdx = -1;     // index into specialParameterTable
+  int FirstIntSpecialParameterIdx = -1; // index into specialParameterTable
+  clang::QualType FirstIntSpecialParameterType;
   size_t NumParams = FD->getNumParams();
-  *IndexOfFirstIterator = NumParams;
+  *IndexOfFirstSpecialParameter = NumParams;
   bool valid = true;
   for (size_t i = 0; i < NumParams; i++) {
     const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
     llvm::StringRef ParamName = PVD->getName();
-    if (ParamName.equals("x")) {
-      slangAssert(mX == NULL);  // We won't be invoked if two 'x' are present.
-      mX = PVD;
-      if (mY != NULL) {
+    int SpecialParameterIdx = lookupSpecialParameter(ParamName);
+    if (SpecialParameterIdx >= 0) {
+      const SpecialParameter &SP = specialParameterTable[SpecialParameterIdx];
+      // We won't be invoked if two parameters of the same name are present.
+      slangAssert(!(mSpecialParameterSignatureMetadata & SP.bitval));
+
+      if (Context->getTargetAPI() < SP.minAPI) {
         Context->ReportError(PVD->getLocation(),
-                             "In compute kernel %0(), parameter 'x' should "
-                             "be defined before parameter 'y'")
-            << FD->getName();
+                             "Compute kernel %0() targeting SDK levels "
+                             "%1-%2 may not use parameter '%3'.")
+            << FD->getName()
+            << SLANG_MINIMUM_TARGET_API
+            << (SP.minAPI - 1)
+            << SP.name;
         valid = false;
       }
-    } else if (ParamName.equals("y")) {
-      slangAssert(mY == NULL);  // We won't be invoked if two 'y' are present.
-      mY = PVD;
+
+      mSpecialParameterSignatureMetadata |= SP.bitval;
+      if (SpecialParameterIdx < LastSpecialParameterIdx) {
+        Context->ReportError(PVD->getLocation(),
+                             "In compute kernel %0(), parameter '%1' must "
+                             "be defined before parameter '%2'.")
+            << FD->getName()
+            << SP.name
+            << specialParameterTable[LastSpecialParameterIdx].name;
+        valid = false;
+      }
+      LastSpecialParameterIdx = SpecialParameterIdx;
+
+      // Ensure that all SPK_INT special parameters have the same type.
+      if (SP.kind == SPK_INT) {
+        clang::QualType SpecialParameterType = PVD->getType();
+        if (FirstIntSpecialParameterIdx >= 0) {
+          if (SpecialParameterType != FirstIntSpecialParameterType) {
+            Context->ReportError(PVD->getLocation(),
+                                 "Parameters '%0' and '%1' must be of the same type. "
+                                 "'%0' is of type '%2' while '%1' is of type '%3'.")
+                << specialParameterTable[FirstIntSpecialParameterIdx].name
+                << SP.name
+                << FirstIntSpecialParameterType.getAsString()
+                << SpecialParameterType.getAsString();
+            valid = false;
+          }
+        } else {
+          FirstIntSpecialParameterIdx = SpecialParameterIdx;
+          FirstIntSpecialParameterType = SpecialParameterType;
+        }
+      }
     } else {
-      // It's neither x nor y.
-      if (*IndexOfFirstIterator < NumParams) {
+      // It's not a special parameter.
+      if (*IndexOfFirstSpecialParameter < NumParams) {
         Context->ReportError(PVD->getLocation(),
                              "In compute kernel %0(), parameter '%1' cannot "
-                             "appear after the 'x' and 'y' parameters")
-            << FD->getName() << ParamName;
+                             "appear after any of the (%2) parameters.")
+            << FD->getName() << ParamName << listSpecialParameters(Context->getTargetAPI());
         valid = false;
       }
       continue;
     }
-    // Validate the data type of x and y.
-    clang::QualType QT = PVD->getType().getCanonicalType();
-    clang::QualType UT = QT.getUnqualifiedType();
-    if (UT != C.UnsignedIntTy && UT != C.IntTy) {
-      Context->ReportError(PVD->getLocation(),
-                           "Parameter '%0' must be of type 'int' or "
-                           "'unsigned int'. It is of type '%1'")
-          << ParamName << PVD->getType().getAsString();
-      valid = false;
+    // Validate the data type of the special parameter.
+    switch (specialParameterTable[SpecialParameterIdx].kind) {
+      case SPK_INT: {
+        clang::QualType QT = PVD->getType().getCanonicalType();
+        clang::QualType UT = QT.getUnqualifiedType();
+        if (UT != C.UnsignedIntTy && UT != C.IntTy) {
+          Context->ReportError(PVD->getLocation(),
+                               "Parameter '%0' must be of type 'int' or "
+                               "'unsigned int'. It is of type '%1'.")
+              << ParamName << PVD->getType().getAsString();
+          valid = false;
+        }
+        break;
+      }
+      case SPK_CTXT: {
+        static const char ExpectedTypeNameMatch[] = "const struct rs_kernel_context_t *";
+        static const char ExpectedTypeNamePrint[] = "rs_kernel_context";
+        clang::QualType QT = PVD->getType().getCanonicalType();
+        clang::QualType UT = QT.getUnqualifiedType();
+        if (UT.getAsString() != ExpectedTypeNameMatch) {
+          Context->ReportError(PVD->getLocation(),
+                               "Parameter '%0' must be of type '%1'. "
+                               "It is of type '%2'.")
+              << ParamName << ExpectedTypeNamePrint << PVD->getType().getAsString();
+          valid = false;
+        }
+        break;
+      }
+      default:
+        slangAssert(!"Unexpected special parameter type");
     }
-    // If this is the first time we find an iterator, save it.
-    if (*IndexOfFirstIterator >= NumParams) {
-      *IndexOfFirstIterator = i;
-    }
-  }
-  // Check that x and y have the same type.
-  if (mX != NULL and mY != NULL) {
-    clang::QualType XType = mX->getType();
-    clang::QualType YType = mY->getType();
-
-    if (XType != YType) {
-      Context->ReportError(mY->getLocation(),
-                           "Parameter 'x' and 'y' must be of the same type. "
-                           "'x' is of type '%0' while 'y' is of type '%1'")
-          << XType.getAsString() << YType.getAsString();
-      valid = false;
+    // If this is the first time we find a special parameter, save it.
+    if (*IndexOfFirstSpecialParameter >= NumParams) {
+      *IndexOfFirstSpecialParameter = i;
     }
   }
   return valid;
@@ -299,30 +412,30 @@
   bool valid = true;
 
   if (mIsKernelStyle) {
-    slangAssert(mOut == NULL);
-    slangAssert(mUsrData == NULL);
+    slangAssert(mOut == nullptr);
+    slangAssert(mUsrData == nullptr);
   } else {
     slangAssert(!mHasReturnType);
   }
 
   // Set up the bitwise metadata encoding for runtime argument passing.
-  // TODO: If this bit field is re-used from C++ code, define the values in a header.
   const bool HasOut = mOut || mHasReturnType;
-  mSignatureMetadata |= (hasIns() ?       0x01 : 0);
-  mSignatureMetadata |= (HasOut ?         0x02 : 0);
-  mSignatureMetadata |= (mUsrData ?       0x04 : 0);
-  mSignatureMetadata |= (mX ?             0x08 : 0);
-  mSignatureMetadata |= (mY ?             0x10 : 0);
-  mSignatureMetadata |= (mIsKernelStyle ? 0x20 : 0);  // pass-by-value
+  mSignatureMetadata |= (hasIns() ?       bcinfo::MD_SIG_In     : 0);
+  mSignatureMetadata |= (HasOut ?         bcinfo::MD_SIG_Out    : 0);
+  mSignatureMetadata |= (mUsrData ?       bcinfo::MD_SIG_Usr    : 0);
+  mSignatureMetadata |= (mIsKernelStyle ? bcinfo::MD_SIG_Kernel : 0);  // pass-by-value
+  mSignatureMetadata |= mSpecialParameterSignatureMetadata;
 
   if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
     // APIs before ICS cannot skip between parameters. It is ok, however, for
     // them to omit further parameters (i.e. skipping X is ok if you skip Y).
-    if (mSignatureMetadata != 0x1f &&  // In, Out, UsrData, X, Y
-        mSignatureMetadata != 0x0f &&  // In, Out, UsrData, X
-        mSignatureMetadata != 0x07 &&  // In, Out, UsrData
-        mSignatureMetadata != 0x03 &&  // In, Out
-        mSignatureMetadata != 0x01) {  // In
+    if (mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
+                               bcinfo::MD_SIG_X | bcinfo::MD_SIG_Y) &&
+        mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
+                               bcinfo::MD_SIG_X) &&
+        mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr) &&
+        mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out) &&
+        mSignatureMetadata != (bcinfo::MD_SIG_In)) {
       Context->ReportError(FD->getLocation(),
                            "Compute kernel %0() targeting SDK levels "
                            "%1-%2 may not skip parameters")
@@ -345,7 +458,7 @@
   FE = new RSExportForEach(Context, Name);
 
   if (!FE->validateAndConstructParams(Context, FD)) {
-    return NULL;
+    return nullptr;
   }
 
   clang::ASTContext &Ctx = Context->getASTContext();
@@ -364,7 +477,7 @@
         C.VoidTy) {
       // In the case of using const void*, we can't reflect an appopriate
       // Java type, so we fall back to just reflecting the ain/aout parameters
-      FE->mUsrData = NULL;
+      FE->mUsrData = nullptr;
     } else {
       clang::RecordDecl *RD =
           clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
@@ -380,8 +493,8 @@
                                    clang::SourceLocation(),
                                    PVD->getIdentifier(),
                                    QT->getPointeeType(),
-                                   NULL,
-                                   /* BitWidth = */ NULL,
+                                   nullptr,
+                                   /* BitWidth = */ nullptr,
                                    /* Mutable = */ false,
                                    /* HasInit = */ clang::ICIS_NoInit);
       RD->addDecl(FD);
@@ -393,11 +506,11 @@
 
       RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
 
-      if (ET == NULL) {
+      if (ET == nullptr) {
         fprintf(stderr, "Failed to export the function %s. There's at least "
                         "one parameter whose type is not supported by the "
                         "reflection\n", FE->getName().c_str());
-        return NULL;
+        return nullptr;
       }
 
       slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
@@ -414,7 +527,7 @@
       RSExportType *InExportType = RSExportType::Create(Context, T);
 
       if (FE->mIsKernelStyle) {
-        slangAssert(InExportType != NULL);
+        slangAssert(InExportType != nullptr);
       }
 
       FE->mInTypes.push_back(InExportType);
diff --git a/slang_rs_export_foreach.h b/slang_rs_export_foreach.h
index f401d19..54b1303 100644
--- a/slang_rs_export_foreach.h
+++ b/slang_rs_export_foreach.h
@@ -57,8 +57,9 @@
   llvm::SmallVector<const clang::ParmVarDecl*, 16> mIns;
   const clang::ParmVarDecl *mOut;
   const clang::ParmVarDecl *mUsrData;
-  const clang::ParmVarDecl *mX;
-  const clang::ParmVarDecl *mY;
+
+  // Accumulator for metadata bits corresponding to special parameters.
+  unsigned int mSpecialParameterSignatureMetadata;
 
   clang::QualType mResultType;  // return type (if present).
   bool mHasReturnType;  // does this kernel have a return type?
@@ -69,9 +70,9 @@
   // TODO(all): Add support for LOD/face when we have them
   RSExportForEach(RSContext *Context, const llvm::StringRef &Name)
     : RSExportable(Context, RSExportable::EX_FOREACH),
-      mName(Name.data(), Name.size()), mParamPacketType(NULL),
-      mOutType(NULL), numParams(0), mSignatureMetadata(0),
-      mOut(NULL), mUsrData(NULL), mX(NULL), mY(NULL),
+      mName(Name.data(), Name.size()), mParamPacketType(nullptr),
+      mOutType(nullptr), numParams(0), mSignatureMetadata(0),
+      mOut(nullptr), mUsrData(nullptr), mSpecialParameterSignatureMetadata(0),
       mResultType(clang::QualType()), mHasReturnType(false),
       mIsKernelStyle(false), mDummyRoot(false) {
   }
@@ -85,9 +86,9 @@
   bool validateAndConstructKernelParams(RSContext *Context,
                                         const clang::FunctionDecl *FD);
 
-  bool validateIterationParameters(RSContext *Context,
-                                   const clang::FunctionDecl *FD,
-                                   size_t *IndexOfFirstIterator);
+  bool validateSpecialParameters(RSContext *Context,
+                                 const clang::FunctionDecl *FD,
+                                 size_t *IndexOfFirstSpecialParameter);
 
   bool setSignatureMetadata(RSContext *Context,
                             const clang::FunctionDecl *FD);
@@ -110,11 +111,11 @@
   }
 
   inline bool hasOut() const {
-    return (mOut != NULL);
+    return (mOut != nullptr);
   }
 
   inline bool hasUsrData() const {
-    return (mUsrData != NULL);
+    return (mUsrData != nullptr);
   }
 
   inline bool hasReturn() const {
@@ -148,13 +149,13 @@
   typedef RSExportRecordType::const_field_iterator const_param_iterator;
 
   inline const_param_iterator params_begin() const {
-    slangAssert((mParamPacketType != NULL) &&
+    slangAssert((mParamPacketType != nullptr) &&
                 "Get parameter from export foreach having no parameter!");
     return mParamPacketType->fields_begin();
   }
 
   inline const_param_iterator params_end() const {
-    slangAssert((mParamPacketType != NULL) &&
+    slangAssert((mParamPacketType != nullptr) &&
                 "Get parameter from export foreach having no parameter!");
     return mParamPacketType->fields_end();
   }
diff --git a/slang_rs_export_func.cpp b/slang_rs_export_func.cpp
index 5fc36f1..070270c 100644
--- a/slang_rs_export_func.cpp
+++ b/slang_rs_export_func.cpp
@@ -55,14 +55,14 @@
   slangAssert(!Name.empty() && "Function must have a name");
 
   if (!ValidateFuncDecl(Context, FD)) {
-    return NULL;
+    return nullptr;
   }
 
   F = new RSExportFunc(Context, Name, FD);
 
   // Initialize mParamPacketType
   if (FD->getNumParams() <= 0) {
-    F->mParamPacketType = NULL;
+    F->mParamPacketType = nullptr;
   } else {
     clang::ASTContext &Ctx = Context->getASTContext();
 
@@ -92,8 +92,8 @@
                                    clang::SourceLocation(),
                                    PVD->getIdentifier(),
                                    PVD->getOriginalType(),
-                                   NULL,
-                                   /* BitWidth = */ NULL,
+                                   nullptr,
+                                   /* BitWidth = */ nullptr,
                                    /* Mutable = */ false,
                                    /* HasInit = */ clang::ICIS_NoInit);
       RD->addDecl(FD);
@@ -107,11 +107,11 @@
     RSExportType *ET =
       RSExportType::Create(Context, T.getTypePtr());
 
-    if (ET == NULL) {
+    if (ET == nullptr) {
       fprintf(stderr, "Failed to export the function %s. There's at least one "
                       "parameter whose type is not supported by the "
                       "reflection\n", F->getName().c_str());
-      return NULL;
+      return nullptr;
     }
 
     slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
@@ -125,12 +125,12 @@
 
 bool
 RSExportFunc::checkParameterPacketType(llvm::StructType *ParamTy) const {
-  if (ParamTy == NULL)
+  if (ParamTy == nullptr)
     return !hasParam();
   else if (!hasParam())
     return false;
 
-  slangAssert(mParamPacketType != NULL);
+  slangAssert(mParamPacketType != nullptr);
 
   const RSExportRecordType *ERT = mParamPacketType;
   // must have same number of elements
diff --git a/slang_rs_export_func.h b/slang_rs_export_func.h
index d680f52..3c0804d 100644
--- a/slang_rs_export_func.h
+++ b/slang_rs_export_func.h
@@ -56,7 +56,7 @@
       mName(Name.data(), Name.size()),
       mMangledName(),
       mShouldMangle(false),
-      mParamPacketType(NULL) {
+      mParamPacketType(nullptr) {
 
     mShouldMangle = Context->getMangleContext().shouldMangleDeclName(FD);
 
@@ -74,12 +74,12 @@
   typedef RSExportRecordType::const_field_iterator const_param_iterator;
 
   inline const_param_iterator params_begin() const {
-    slangAssert((mParamPacketType != NULL) &&
+    slangAssert((mParamPacketType != nullptr) &&
                 "Get parameter from export function having no parameter!");
     return mParamPacketType->fields_begin();
   }
   inline const_param_iterator params_end() const {
-    slangAssert((mParamPacketType != NULL) &&
+    slangAssert((mParamPacketType != nullptr) &&
                 "Get parameter from export function having no parameter!");
     return mParamPacketType->fields_end();
   }
@@ -98,7 +98,7 @@
 
   // Check whether the given ParamsPacket type (in LLVM type) is "size
   // equivalent" to the one obtained from getParamPacketType(). If the @Params
-  // is NULL, means there must be no any parameters.
+  // is nullptr, means there must be no any parameters.
   bool checkParameterPacketType(llvm::StructType *ParamTy) const;
 };  // RSExportFunc
 
diff --git a/slang_rs_export_type.cpp b/slang_rs_export_type.cpp
index 4348ea0..8a8dbe0 100644
--- a/slang_rs_export_type.cpp
+++ b/slang_rs_export_type.cpp
@@ -59,31 +59,31 @@
     {PrimitiveDataType, "UNSIGNED_32", "U32", 32, "uint32_t", "long", "UInt", "Long", true},
     {PrimitiveDataType, "UNSIGNED_64", "U64", 64, "uint64_t", "long", "ULong", "Long", false},
 
-    {PrimitiveDataType, "BOOLEAN", "BOOLEAN", 8, "bool", "boolean", NULL, NULL, false},
+    {PrimitiveDataType, "BOOLEAN", "BOOLEAN", 8, "bool", "boolean", nullptr, nullptr, false},
 
-    {PrimitiveDataType, "UNSIGNED_5_6_5", NULL, 16, NULL, NULL, NULL, NULL, false},
-    {PrimitiveDataType, "UNSIGNED_5_5_5_1", NULL, 16, NULL, NULL, NULL, NULL, false},
-    {PrimitiveDataType, "UNSIGNED_4_4_4_4", NULL, 16, NULL, NULL, NULL, NULL, false},
+    {PrimitiveDataType, "UNSIGNED_5_6_5", nullptr, 16, nullptr, nullptr, nullptr, nullptr, false},
+    {PrimitiveDataType, "UNSIGNED_5_5_5_1", nullptr, 16, nullptr, nullptr, nullptr, nullptr, false},
+    {PrimitiveDataType, "UNSIGNED_4_4_4_4", nullptr, 16, nullptr, nullptr, nullptr, nullptr, false},
 
-    {MatrixDataType, "MATRIX_2X2", NULL, 4*32, "rsMatrix_2x2", "Matrix2f", NULL, NULL, false},
-    {MatrixDataType, "MATRIX_3X3", NULL, 9*32, "rsMatrix_3x3", "Matrix3f", NULL, NULL, false},
-    {MatrixDataType, "MATRIX_4X4", NULL, 16*32, "rsMatrix_4x4", "Matrix4f", NULL, NULL, false},
+    {MatrixDataType, "MATRIX_2X2", nullptr, 4*32, "rsMatrix_2x2", "Matrix2f", nullptr, nullptr, false},
+    {MatrixDataType, "MATRIX_3X3", nullptr, 9*32, "rsMatrix_3x3", "Matrix3f", nullptr, nullptr, false},
+    {MatrixDataType, "MATRIX_4X4", nullptr, 16*32, "rsMatrix_4x4", "Matrix4f", nullptr, nullptr, false},
 
     // RS object types are 32 bits in 32-bit RS, but 256 bits in 64-bit RS.
     // This is handled specially by the GetSizeInBits() method.
-    {ObjectDataType, "RS_ELEMENT", "ELEMENT", 32, "Element", "Element", NULL, NULL, false},
-    {ObjectDataType, "RS_TYPE", "TYPE", 32, "Type", "Type", NULL, NULL, false},
-    {ObjectDataType, "RS_ALLOCATION", "ALLOCATION", 32, "Allocation", "Allocation", NULL, NULL, false},
-    {ObjectDataType, "RS_SAMPLER", "SAMPLER", 32, "Sampler", "Sampler", NULL, NULL, false},
-    {ObjectDataType, "RS_SCRIPT", "SCRIPT", 32, "Script", "Script", NULL, NULL, false},
-    {ObjectDataType, "RS_MESH", "MESH", 32, "Mesh", "Mesh", NULL, NULL, false},
-    {ObjectDataType, "RS_PATH", "PATH", 32, "Path", "Path", NULL, NULL, false},
+    {ObjectDataType, "RS_ELEMENT", "ELEMENT", 32, "Element", "Element", nullptr, nullptr, false},
+    {ObjectDataType, "RS_TYPE", "TYPE", 32, "Type", "Type", nullptr, nullptr, false},
+    {ObjectDataType, "RS_ALLOCATION", "ALLOCATION", 32, "Allocation", "Allocation", nullptr, nullptr, false},
+    {ObjectDataType, "RS_SAMPLER", "SAMPLER", 32, "Sampler", "Sampler", nullptr, nullptr, false},
+    {ObjectDataType, "RS_SCRIPT", "SCRIPT", 32, "Script", "Script", nullptr, nullptr, false},
+    {ObjectDataType, "RS_MESH", "MESH", 32, "Mesh", "Mesh", nullptr, nullptr, false},
+    {ObjectDataType, "RS_PATH", "PATH", 32, "Path", "Path", nullptr, nullptr, false},
 
-    {ObjectDataType, "RS_PROGRAM_FRAGMENT", "PROGRAM_FRAGMENT", 32, "ProgramFragment", "ProgramFragment", NULL, NULL, false},
-    {ObjectDataType, "RS_PROGRAM_VERTEX", "PROGRAM_VERTEX", 32, "ProgramVertex", "ProgramVertex", NULL, NULL, false},
-    {ObjectDataType, "RS_PROGRAM_RASTER", "PROGRAM_RASTER", 32, "ProgramRaster", "ProgramRaster", NULL, NULL, false},
-    {ObjectDataType, "RS_PROGRAM_STORE", "PROGRAM_STORE", 32, "ProgramStore", "ProgramStore", NULL, NULL, false},
-    {ObjectDataType, "RS_FONT", "FONT", 32, "Font", "Font", NULL, NULL, false}
+    {ObjectDataType, "RS_PROGRAM_FRAGMENT", "PROGRAM_FRAGMENT", 32, "ProgramFragment", "ProgramFragment", nullptr, nullptr, false},
+    {ObjectDataType, "RS_PROGRAM_VERTEX", "PROGRAM_VERTEX", 32, "ProgramVertex", "ProgramVertex", nullptr, nullptr, false},
+    {ObjectDataType, "RS_PROGRAM_RASTER", "PROGRAM_RASTER", 32, "ProgramRaster", "ProgramRaster", nullptr, nullptr, false},
+    {ObjectDataType, "RS_PROGRAM_STORE", "PROGRAM_STORE", 32, "ProgramStore", "ProgramStore", nullptr, nullptr, false},
+    {ObjectDataType, "RS_FONT", "FONT", 32, "Font", "Font", nullptr, nullptr, false}
 };
 
 const int kMaxVectorSize = 4;
@@ -201,7 +201,7 @@
   if (ElementType->isArrayType()) {
     ReportTypeError(Context, VD, TopLevelRecord,
                     "multidimensional arrays cannot be exported: '%0'");
-    return NULL;
+    return nullptr;
   } else if (ElementType->isExtVectorType()) {
     const clang::ExtVectorType *EVT =
         static_cast<const clang::ExtVectorType*>(ElementType);
@@ -211,19 +211,19 @@
     if (!RSExportPrimitiveType::IsPrimitiveType(BaseElementType)) {
       ReportTypeError(Context, VD, TopLevelRecord,
         "vectors of non-primitive types cannot be exported: '%0'");
-      return NULL;
+      return nullptr;
     }
 
     if (numElements == 3 && CAT->getSize() != 1) {
       ReportTypeError(Context, VD, TopLevelRecord,
         "arrays of width 3 vector types cannot be exported: '%0'");
-      return NULL;
+      return nullptr;
     }
   }
 
   if (TypeExportableHelper(ElementType, SPS, Context, VD,
-                           TopLevelRecord) == NULL) {
-    return NULL;
+                           TopLevelRecord) == nullptr) {
+    return nullptr;
   } else {
     return CAT;
   }
@@ -235,7 +235,7 @@
       return &BuiltinInfoTable[i];
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 static const clang::Type *TypeExportableHelper(
@@ -245,8 +245,8 @@
     clang::VarDecl const *VD,
     clang::RecordDecl const *TopLevelRecord) {
   // Normalize first
-  if ((T = GetCanonicalType(T)) == NULL)
-    return NULL;
+  if ((T = GetCanonicalType(T)) == nullptr)
+    return nullptr;
 
   if (SPS.count(T))
     return T;
@@ -256,7 +256,7 @@
   switch (T->getTypeClass()) {
     case clang::Type::Builtin: {
       const clang::BuiltinType *BT = static_cast<const clang::BuiltinType*>(CTI);
-      return FindBuiltinType(BT->getKind()) == NULL ? NULL : T;
+      return FindBuiltinType(BT->getKind()) == nullptr ? nullptr : T;
     }
     case clang::Type::Record: {
       if (RSExportPrimitiveType::GetRSSpecificType(T) != DataTypeUnknown) {
@@ -267,19 +267,19 @@
       if (T->isUnionType()) {
         ReportTypeError(Context, VD, T->getAsUnionType()->getDecl(),
                         "unions cannot be exported: '%0'");
-        return NULL;
+        return nullptr;
       } else if (!T->isStructureType()) {
         slangAssert(false && "Unknown type cannot be exported");
-        return NULL;
+        return nullptr;
       }
 
       clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
-      if (RD != NULL) {
+      if (RD != nullptr) {
         RD = RD->getDefinition();
-        if (RD == NULL) {
-          ReportTypeError(Context, NULL, T->getAsStructureType()->getDecl(),
+        if (RD == nullptr) {
+          ReportTypeError(Context, nullptr, T->getAsStructureType()->getDecl(),
                           "struct is not defined in this module");
-          return NULL;
+          return nullptr;
         }
       }
 
@@ -287,14 +287,14 @@
         TopLevelRecord = RD;
       }
       if (RD->getName().empty()) {
-        ReportTypeError(Context, NULL, RD,
+        ReportTypeError(Context, nullptr, RD,
                         "anonymous structures cannot be exported");
-        return NULL;
+        return nullptr;
       }
 
       // Fast check
       if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
-        return NULL;
+        return nullptr;
 
       // Insert myself into checking set
       SPS.insert(T);
@@ -309,7 +309,7 @@
         FT = GetCanonicalType(FT);
 
         if (!TypeExportableHelper(FT, SPS, Context, VD, TopLevelRecord)) {
-          return NULL;
+          return nullptr;
         }
 
         // We don't support bit fields yet
@@ -320,7 +320,7 @@
               FD->getLocation(),
               "bit fields are not able to be exported: '%0.%1'")
               << RD->getName() << FD->getName();
-          return NULL;
+          return nullptr;
         }
       }
 
@@ -330,7 +330,7 @@
       if (TopLevelRecord) {
         ReportTypeError(Context, VD, TopLevelRecord,
             "structures containing pointers cannot be exported: '%0'");
-        return NULL;
+        return nullptr;
       }
 
       const clang::PointerType *PT = static_cast<const clang::PointerType*>(CTI);
@@ -339,14 +339,14 @@
       if (PointeeType->getTypeClass() == clang::Type::Pointer) {
         ReportTypeError(Context, VD, TopLevelRecord,
             "multiple levels of pointers cannot be exported: '%0'");
-        return NULL;
+        return nullptr;
       }
       // We don't support pointer with array-type pointee or unsupported pointee
       // type
       if (PointeeType->isArrayType() ||
           (TypeExportableHelper(PointeeType, SPS, Context, VD,
-                                TopLevelRecord) == NULL))
-        return NULL;
+                                TopLevelRecord) == nullptr))
+        return nullptr;
       else
         return T;
     }
@@ -355,15 +355,15 @@
               static_cast<const clang::ExtVectorType*>(CTI);
       // Only vector with size 2, 3 and 4 are supported.
       if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4)
-        return NULL;
+        return nullptr;
 
       // Check base element type
       const clang::Type *ElementType = GetExtVectorElementType(EVT);
 
       if ((ElementType->getTypeClass() != clang::Type::Builtin) ||
           (TypeExportableHelper(ElementType, SPS, Context, VD,
-                                TopLevelRecord) == NULL))
-        return NULL;
+                                TopLevelRecord) == nullptr))
+        return nullptr;
       else
         return T;
     }
@@ -381,25 +381,26 @@
     }
     default: {
       slangAssert(false && "Unknown type cannot be validated");
-      return NULL;
+      return nullptr;
     }
   }
 }
 
 // Return the type that can be used to create RSExportType, will always return
-// the canonical type
-// If the Type T is not exportable, this function returns NULL. DiagEngine is
-// used to generate proper Clang diagnostic messages when a
-// non-exportable type is detected. TopLevelRecord is used to capture the
-// highest struct (in the case of a nested hierarchy) for detecting other
-// types that cannot be exported (mostly pointers within a struct).
+// the canonical type.
+//
+// If the Type T is not exportable, this function returns nullptr. DiagEngine is
+// used to generate proper Clang diagnostic messages when a non-exportable type
+// is detected. TopLevelRecord is used to capture the highest struct (in the
+// case of a nested hierarchy) for detecting other types that cannot be exported
+// (mostly pointers within a struct).
 static const clang::Type *TypeExportable(const clang::Type *T,
                                          slang::RSContext *Context,
                                          const clang::VarDecl *VD) {
   llvm::SmallPtrSet<const clang::Type*, 8> SPS =
       llvm::SmallPtrSet<const clang::Type*, 8>();
 
-  return TypeExportableHelper(T, SPS, Context, VD, NULL);
+  return TypeExportableHelper(T, SPS, Context, VD, nullptr);
 }
 
 static bool ValidateRSObjectInVarDecl(slang::RSContext *Context,
@@ -414,7 +415,7 @@
         // Only if we are not a pointer to an object.
         const clang::Type *T = GetCanonicalType(VD->getType().getTypePtr());
         if (T->getTypeClass() != clang::Type::Pointer) {
-          ReportTypeError(Context, VD, NULL,
+          ReportTypeError(Context, VD, nullptr,
                           "arrays/structures containing RS object types "
                           "cannot be exported in target API < %1: '%0'",
                           SLANG_JB_TARGET_API);
@@ -452,7 +453,7 @@
     clang::RecordDecl *UnionDecl,
     unsigned int TargetAPI,
     bool IsFilterscript) {
-  if ((T = GetCanonicalType(T)) == NULL)
+  if ((T = GetCanonicalType(T)) == nullptr)
     return true;
 
   if (SPS.count(T))
@@ -463,7 +464,7 @@
   switch (T->getTypeClass()) {
     case clang::Type::Record: {
       if (RSExportPrimitiveType::IsRSObjectType(T)) {
-        clang::VarDecl *VD = (ND ? llvm::dyn_cast<clang::VarDecl>(ND) : NULL);
+        clang::VarDecl *VD = (ND ? llvm::dyn_cast<clang::VarDecl>(ND) : nullptr);
         if (VD && !ValidateRSObjectInVarDecl(Context, VD, InCompositeType,
                                              TargetAPI)) {
           return false;
@@ -474,13 +475,13 @@
         if (!UnionDecl) {
           return true;
         } else if (RSExportPrimitiveType::IsRSObjectType(T)) {
-          ReportTypeError(Context, NULL, UnionDecl,
+          ReportTypeError(Context, nullptr, UnionDecl,
               "unions containing RS object types are not allowed");
           return false;
         }
       }
 
-      clang::RecordDecl *RD = NULL;
+      clang::RecordDecl *RD = nullptr;
 
       // Check internal struct
       if (T->isUnionType()) {
@@ -493,9 +494,9 @@
         return false;
       }
 
-      if (RD != NULL) {
+      if (RD != nullptr) {
         RD = RD->getDefinition();
-        if (RD == NULL) {
+        if (RD == nullptr) {
           // FIXME
           return true;
         }
@@ -583,7 +584,7 @@
           EVT->getNumElements() == 3 &&
           ND &&
           ND->getFormalLinkage() == clang::ExternalLinkage) {
-        ReportTypeError(Context, ND, NULL,
+        ReportTypeError(Context, ND, nullptr,
                         "structs containing vectors of dimension 3 cannot "
                         "be exported at this API level: '%0'");
         return false;
@@ -624,7 +625,7 @@
                                  llvm::StringRef &TypeName,
                                  RSContext *Context,
                                  const clang::VarDecl *VD) {
-  if ((T = TypeExportable(T, Context, VD)) == NULL) {
+  if ((T = TypeExportable(T, Context, VD)) == nullptr) {
     return false;
   }
   // Get type name
@@ -650,7 +651,7 @@
   llvm::SmallPtrSet<const clang::Type*, 8> SPS =
       llvm::SmallPtrSet<const clang::Type*, 8>();
 
-  return ValidateTypeHelper(Context, C, T, ND, Loc, SPS, false, NULL, TargetAPI,
+  return ValidateTypeHelper(Context, C, T, ND, Loc, SPS, false, nullptr, TargetAPI,
                             IsFilterscript);
   return true;
 }
@@ -668,16 +669,16 @@
     clang::QualType T = DD->getType();
 
     if (T.isNull())
-      return NULL;
+      return nullptr;
     else
       return T.getTypePtr();
   }
-  return NULL;
+  return nullptr;
 }
 
 llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
   T = GetCanonicalType(T);
-  if (T == NULL)
+  if (T == nullptr)
     return llvm::StringRef();
 
   const clang::Type *CTI = T->getCanonicalTypeInternal().getTypePtr();
@@ -686,7 +687,7 @@
     case clang::Type::Builtin: {
       const clang::BuiltinType *BT = static_cast<const clang::BuiltinType*>(CTI);
       BuiltinInfo *info = FindBuiltinType(BT->getKind());
-      if (info != NULL) {
+      if (info != nullptr) {
         return info->cname[0];
       }
       slangAssert(false && "Unknown data type of the builtin");
@@ -702,7 +703,7 @@
 
       llvm::StringRef Name = RD->getName();
       if (Name.empty()) {
-        if (RD->getTypedefNameForAnonDecl() != NULL) {
+        if (RD->getTypedefNameForAnonDecl() != nullptr) {
           Name = RD->getTypedefNameForAnonDecl()->getName();
         }
 
@@ -712,7 +713,7 @@
                    RE = RD->redecls_end();
                RI != RE;
                RI++) {
-            slangAssert(*RI != NULL && "cannot be NULL object");
+            slangAssert(*RI != nullptr && "cannot be NULL object");
 
             Name = (*RI)->getName();
             if (!Name.empty())
@@ -727,7 +728,7 @@
       const clang::PointerType *P = static_cast<const clang::PointerType*>(CTI);
       const clang::Type *PT = GetPointeeType(P);
       llvm::StringRef PointeeName;
-      if (NormalizeType(PT, PointeeName, NULL, NULL)) {
+      if (NormalizeType(PT, PointeeName, nullptr, nullptr)) {
         char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
         Name[0] = '*';
         memcpy(Name + 1, PointeeName.data(), PointeeName.size());
@@ -768,7 +769,7 @@
 
   const clang::Type *CTI = T->getCanonicalTypeInternal().getTypePtr();
 
-  RSExportType *ET = NULL;
+  RSExportType *ET = nullptr;
   switch (T->getTypeClass()) {
     case clang::Type::Record: {
       DataType dt = RSExportPrimitiveType::GetRSSpecificType(TypeName);
@@ -848,10 +849,10 @@
 
 RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
   llvm::StringRef TypeName;
-  if (NormalizeType(T, TypeName, Context, NULL)) {
+  if (NormalizeType(T, TypeName, Context, nullptr)) {
     return Create(Context, T, TypeName);
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
@@ -876,7 +877,7 @@
       // Make a copy on Name since memory stored @Name is either allocated in
       // ASTContext or allocated in GetTypeName which will be destroyed later.
       mName(Name.data(), Name.size()),
-      mLLVMType(NULL) {
+      mLLVMType(nullptr) {
   // Don't cache the type whose name start with '<'. Those type failed to
   // get their name since constructing their name in GetTypeName() requiring
   // complicated work.
@@ -891,7 +892,7 @@
   if (!RSExportable::keep())
     return false;
   // Invalidate converted LLVM type.
-  mLLVMType = NULL;
+  mLLVMType = nullptr;
   return true;
 }
 
@@ -908,7 +909,7 @@
 RSExportPrimitiveType::RSSpecificTypeMap;
 
 bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
-  if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin))
+  if ((T != nullptr) && (T->getTypeClass() == clang::Type::Builtin))
     return true;
   else
     return false;
@@ -921,8 +922,8 @@
 
   if (RSSpecificTypeMap->empty()) {
     for (int i = 0; i < MatrixAndObjectDataTypesCount; i++) {
-      RSSpecificTypeMap->GetOrCreateValue(MatrixAndObjectDataTypes[i].name,
-                                          MatrixAndObjectDataTypes[i].dataType);
+      (*RSSpecificTypeMap)[MatrixAndObjectDataTypes[i].name] =
+          MatrixAndObjectDataTypes[i].dataType;
     }
   }
 
@@ -935,7 +936,7 @@
 
 DataType RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) {
   T = GetCanonicalType(T);
-  if ((T == NULL) || (T->getTypeClass() != clang::Type::Record))
+  if ((T == nullptr) || (T->getTypeClass() != clang::Type::Record))
     return DataTypeUnknown;
 
   return GetRSSpecificType( RSExportType::GetTypeName(T) );
@@ -1029,7 +1030,7 @@
 
 DataType
 RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) {
-  if (T == NULL)
+  if (T == nullptr)
     return DataTypeUnknown;
 
   switch (T->getTypeClass()) {
@@ -1037,7 +1038,7 @@
       const clang::BuiltinType *BT =
               static_cast<const clang::BuiltinType*>(T->getCanonicalTypeInternal().getTypePtr());
       BuiltinInfo *info = FindBuiltinType(BT->getKind());
-      if (info != NULL) {
+      if (info != nullptr) {
         return info->type;
       }
       // The size of type WChar depend on platform so we abandon the support
@@ -1068,7 +1069,7 @@
   DataType DT = GetDataType(Context, T);
 
   if ((DT == DataTypeUnknown) || TypeName.empty())
-    return NULL;
+    return nullptr;
   else
     return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
                                      DT, Normalized);
@@ -1077,11 +1078,11 @@
 RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
                                                      const clang::Type *T) {
   llvm::StringRef TypeName;
-  if (RSExportType::NormalizeType(T, TypeName, Context, NULL)
+  if (RSExportType::NormalizeType(T, TypeName, Context, nullptr)
       && IsPrimitiveType(T)) {
     return Create(Context, T, TypeName);
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
@@ -1150,7 +1151,7 @@
     }
   }
 
-  return NULL;
+  return nullptr;
 }
 
 bool RSExportPrimitiveType::equals(const RSExportable *E) const {
@@ -1162,7 +1163,7 @@
   if (DT > DataTypeUnknown && DT < DataTypeMax) {
     return &gReflectionTypes[DT];
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
@@ -1183,9 +1184,9 @@
                     Context->getASTContext().IntTy.getTypePtr());
   }
 
-  if (PointeeET == NULL) {
+  if (PointeeET == nullptr) {
     // Error diagnostic is emitted for corresponding pointee type
-    return NULL;
+    return nullptr;
   }
 
   return new RSExportPointerType(Context, TypeName, PointeeET);
@@ -1227,7 +1228,7 @@
     return name;
 
   BuiltinInfo *info = FindBuiltinType(BT->getKind());
-  if (info != NULL) {
+  if (info != nullptr) {
     int I = EVT->getNumElements() - 1;
     if (I < kMaxVectorSize) {
       name = info->cname[I];
@@ -1242,7 +1243,7 @@
                                                const clang::ExtVectorType *EVT,
                                                const llvm::StringRef &TypeName,
                                                bool Normalized) {
-  slangAssert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector);
+  slangAssert(EVT != nullptr && EVT->getTypeClass() == clang::Type::ExtVector);
 
   const clang::Type *ElementType = GetExtVectorElementType(EVT);
   DataType DT = RSExportPrimitiveType::GetDataType(Context, ElementType);
@@ -1254,7 +1255,7 @@
                                   Normalized,
                                   EVT->getNumElements());
   else
-    return NULL;
+    return nullptr;
 }
 
 llvm::Type *RSExportVectorType::convertToLLVMType() const {
@@ -1273,37 +1274,37 @@
                                                const clang::RecordType *RT,
                                                const llvm::StringRef &TypeName,
                                                unsigned Dim) {
-  slangAssert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record));
+  slangAssert((RT != nullptr) && (RT->getTypeClass() == clang::Type::Record));
   slangAssert((Dim > 1) && "Invalid dimension of matrix");
 
   // Check whether the struct rs_matrix is in our expected form (but assume it's
   // correct if we're not sure whether it's correct or not)
   const clang::RecordDecl* RD = RT->getDecl();
   RD = RD->getDefinition();
-  if (RD != NULL) {
+  if (RD != nullptr) {
     // Find definition, perform further examination
     if (RD->field_empty()) {
       Context->ReportError(
           RD->getLocation(),
           "invalid matrix struct: must have 1 field for saving values: '%0'")
           << RD->getName();
-      return NULL;
+      return nullptr;
     }
 
     clang::RecordDecl::field_iterator FIT = RD->field_begin();
     const clang::FieldDecl *FD = *FIT;
     const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
-    if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
+    if ((FT == nullptr) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
       Context->ReportError(RD->getLocation(),
                            "invalid matrix struct: first field should"
                            " be an array with constant size: '%0'")
           << RD->getName();
-      return NULL;
+      return nullptr;
     }
     const clang::ConstantArrayType *CAT =
       static_cast<const clang::ConstantArrayType *>(FT);
     const clang::Type *ElementType = GetConstantArrayElementType(CAT);
-    if ((ElementType == NULL) ||
+    if ((ElementType == nullptr) ||
         (ElementType->getTypeClass() != clang::Type::Builtin) ||
         (static_cast<const clang::BuiltinType *>(ElementType)->getKind() !=
          clang::BuiltinType::Float)) {
@@ -1311,7 +1312,7 @@
                            "invalid matrix struct: first field "
                            "should be a float array: '%0'")
           << RD->getName();
-      return NULL;
+      return nullptr;
     }
 
     if (CAT->getSize() != Dim * Dim) {
@@ -1319,7 +1320,7 @@
                            "invalid matrix struct: first field "
                            "should be an array with size %0: '%1'")
           << (Dim * Dim) << (RD->getName());
-      return NULL;
+      return nullptr;
     }
 
     FIT++;
@@ -1328,7 +1329,7 @@
                            "invalid matrix struct: must have "
                            "exactly 1 field: '%0'")
           << RD->getName();
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -1356,7 +1357,7 @@
 RSExportConstantArrayType
 *RSExportConstantArrayType::Create(RSContext *Context,
                                    const clang::ConstantArrayType *CAT) {
-  slangAssert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray);
+  slangAssert(CAT != nullptr && CAT->getTypeClass() == clang::Type::ConstantArray);
 
   slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large");
 
@@ -1366,8 +1367,8 @@
   const clang::Type *ElementType = GetConstantArrayElementType(CAT);
   RSExportType *ElementET = RSExportType::Create(Context, ElementType);
 
-  if (ElementET == NULL) {
-    return NULL;
+  if (ElementET == nullptr) {
+    return nullptr;
   }
 
   return new RSExportConstantArrayType(Context,
@@ -1399,22 +1400,22 @@
                                                const clang::RecordType *RT,
                                                const llvm::StringRef &TypeName,
                                                bool mIsArtificial) {
-  slangAssert(RT != NULL && RT->getTypeClass() == clang::Type::Record);
+  slangAssert(RT != nullptr && RT->getTypeClass() == clang::Type::Record);
 
   const clang::RecordDecl *RD = RT->getDecl();
   slangAssert(RD->isStruct());
 
   RD = RD->getDefinition();
-  if (RD == NULL) {
+  if (RD == nullptr) {
     slangAssert(false && "struct is not defined in this module");
-    return NULL;
+    return nullptr;
   }
 
   // Struct layout construct by clang. We rely on this for obtaining the
   // alloc size of a struct and offset of every field in that struct.
   const clang::ASTRecordLayout *RL =
       &Context->getASTContext().getASTRecordLayout(RD);
-  slangAssert((RL != NULL) &&
+  slangAssert((RL != nullptr) &&
       "Failed to retrieve the struct layout from Clang.");
 
   RSExportRecordType *ERT =
@@ -1436,13 +1437,13 @@
     clang::FieldDecl *FD = *FI;
 
     if (FD->isBitField()) {
-      return NULL;
+      return nullptr;
     }
 
     // Type
     RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
 
-    if (ET != NULL) {
+    if (ET != nullptr) {
       ERT->mFields.push_back(
           new Field(ET, FD->getName(), ERT,
                     static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
@@ -1450,7 +1451,7 @@
       Context->ReportError(RD->getLocation(),
                            "field type cannot be exported: '%0.%1'")
           << RD->getName() << FD->getName();
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -1475,10 +1476,10 @@
   llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(),
                                                FieldTypes,
                                                mIsPacked);
-  if (ST != NULL) {
+  if (ST != nullptr) {
     return ST;
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
diff --git a/slang_rs_export_type.h b/slang_rs_export_type.h
index afd2db2..d9bad8c 100644
--- a/slang_rs_export_type.h
+++ b/slang_rs_export_type.h
@@ -35,8 +35,8 @@
 
 
 inline const clang::Type* GetCanonicalType(const clang::Type* T) {
-  if (T == NULL) {
-    return  NULL;
+  if (T == nullptr) {
+    return  nullptr;
   }
   return T->getCanonicalTypeInternal().getTypePtr();
 }
@@ -46,22 +46,22 @@
 }
 
 inline const clang::Type* GetExtVectorElementType(const clang::ExtVectorType *T) {
-  if (T == NULL) {
-    return NULL;
+  if (T == nullptr) {
+    return nullptr;
   }
   return GetCanonicalType(T->getElementType());
 }
 
 inline const clang::Type* GetPointeeType(const clang::PointerType *T) {
-  if (T == NULL) {
-    return NULL;
+  if (T == nullptr) {
+    return nullptr;
   }
   return GetCanonicalType(T->getPointeeType());
 }
 
 inline const clang::Type* GetConstantArrayElementType(const clang::ConstantArrayType *T) {
-  if (T == NULL) {
-    return NULL;
+  if (T == nullptr) {
+    return nullptr;
   }
   return GetCanonicalType(T->getElementType());
 }
@@ -257,7 +257,7 @@
   virtual unsigned getSize() const { return 1; }
 
   inline llvm::Type *getLLVMType() const {
-    if (mLLVMType == NULL)
+    if (mLLVMType == nullptr)
       mLLVMType = convertToLLVMType();
     return mLLVMType;
   }
@@ -591,7 +591,7 @@
              E = mFields.end();
          I != E;
          I++)
-      if (*I != NULL)
+      if (*I != nullptr)
         delete *I;
   }
 };  // RSExportRecordType
diff --git a/slang_rs_export_var.cpp b/slang_rs_export_var.cpp
index 3df28af..0d9e614 100644
--- a/slang_rs_export_var.cpp
+++ b/slang_rs_export_var.cpp
@@ -38,7 +38,7 @@
       mNumInits(0) {
   // mInit - Evaluate initializer expression
   const clang::Expr *Initializer = VD->getAnyInitializer();
-  if (Initializer != NULL) {
+  if (Initializer != nullptr) {
     switch (ET->getClass()) {
       case RSExportType::ExportClassPrimitive:
       case RSExportType::ExportClassVector: {
diff --git a/slang_rs_exportable.cpp b/slang_rs_exportable.cpp
index 53c1fbb..4a843ab 100644
--- a/slang_rs_exportable.cpp
+++ b/slang_rs_exportable.cpp
@@ -22,12 +22,12 @@
   if (isKeep())
     return false;
   // Invalidate associated Context.
-  mContext = NULL;
+  mContext = nullptr;
   return true;
 }
 
 bool RSExportable::equals(const RSExportable *E) const {
-  return ((E == NULL) ? false : (mK == E->mK));
+  return ((E == nullptr) ? false : (mK == E->mK));
 }
 
 }  // namespace slang
diff --git a/slang_rs_exportable.h b/slang_rs_exportable.h
index 8b51182..0871be3 100644
--- a/slang_rs_exportable.h
+++ b/slang_rs_exportable.h
@@ -50,7 +50,7 @@
   // responsibility is then transferred to the object who invoked this function.
   // Return false if the exportable is kept or failed to keep.
   virtual bool keep();
-  inline bool isKeep() const { return (mContext == NULL); }
+  inline bool isKeep() const { return (mContext == nullptr); }
 
   virtual bool equals(const RSExportable *E) const;
 
diff --git a/slang_rs_object_ref_count.cpp b/slang_rs_object_ref_count.cpp
index f0ac22d..47db22f 100644
--- a/slang_rs_object_ref_count.cpp
+++ b/slang_rs_object_ref_count.cpp
@@ -42,8 +42,8 @@
 
 void RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
   for (unsigned i = 0; i < DataTypeMax; i++) {
-    RSSetObjectFD[i] = NULL;
-    RSClearObjectFD[i] = NULL;
+    RSSetObjectFD[i] = nullptr;
+    RSClearObjectFD[i] = nullptr;
   }
 
   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
@@ -151,7 +151,7 @@
   }
   slangAssert(Once <= 1);
 
-  // When S is NULL, we are appending to the end of the CompoundStmt.
+  // When S is nullptr, we are appending to the end of the CompoundStmt.
   if (!S) {
     slangAssert(Once == 0);
     std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
@@ -218,7 +218,7 @@
   // the replacement. It also finishes up by appending the destructor to the
   // current outermost CompoundStmt.
   void InsertDestructors() {
-    clang::Stmt *S = NULL;
+    clang::Stmt *S = nullptr;
     clang::SourceManager &SM = mCtx.getSourceManager();
     std::list<clang::Stmt *> StmtList;
     StmtList.push_back(mDtorStmt);
@@ -244,7 +244,7 @@
     clang::CompoundStmt *CS =
       llvm::dyn_cast<clang::CompoundStmt>(mOuterStmt);
     slangAssert(CS);
-    AppendAfterStmt(mCtx, CS, NULL, StmtList);
+    AppendAfterStmt(mCtx, CS, nullptr, StmtList);
   }
 
   void VisitStmt(clang::Stmt *S);
@@ -358,7 +358,7 @@
               "Should not be destroying arrays with this function");
 
   clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
-  slangAssert((ClearObjectFD != NULL) &&
+  slangAssert((ClearObjectFD != nullptr) &&
               "rsClearObject doesn't cover all RS object types");
 
   clang::QualType ClearObjectFDType = ClearObjectFD->getType();
@@ -391,14 +391,14 @@
                                  ClearObjectFD->getLocation(),
                                  ClearObjectFDType,
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   clang::Expr *RSClearObjectFP =
       clang::ImplicitCastExpr::Create(C,
                                       C.getPointerType(ClearObjectFDType),
                                       clang::CK_FunctionToPointerDecay,
                                       RefRSClearObjectFD,
-                                      NULL,
+                                      nullptr,
                                       clang::VK_RValue);
 
   llvm::SmallVector<clang::Expr*, 1> ArgList;
@@ -445,11 +445,11 @@
   // Actually extract out the base RS object type for use later
   BaseType = BaseType->getArrayElementTypeNoTypeQual();
 
-  clang::Stmt *StmtArray[2] = {NULL};
+  clang::Stmt *StmtArray[2] = {nullptr};
   int StmtCtr = 0;
 
   if (NumArrayElements <= 0) {
-    return NULL;
+    return nullptr;
   }
 
   // Example destructor loop for "rs_font fontArr[10];"
@@ -463,7 +463,7 @@
   //     (BinaryOperator 'int' '<'
   //       (DeclRefExpr 'int' Var='rsIntIter')
   //       (IntegerLiteral 'int' 10)
-  //     NULL << CondVar >>
+  //     nullptr << CondVar >>
   //     (UnaryOperator 'int' postfix '++'
   //       (DeclRefExpr 'int' Var='rsIntIter'))
   //     (CallExpr 'void'
@@ -505,7 +505,7 @@
                                  Loc,
                                  C.IntTy,
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
       llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
@@ -551,7 +551,7 @@
           C.getPointerType(BaseType->getCanonicalTypeInternal()),
           clang::CK_ArrayToPointerDecay,
           RefRSArr,
-          NULL,
+          nullptr,
           clang::VK_RValue);
 
   clang::Expr *RefRSArrPtrSubscript =
@@ -564,7 +564,7 @@
 
   DataType DT = RSExportPrimitiveType::GetRSSpecificType(BaseType);
 
-  clang::Stmt *RSClearObjectCall = NULL;
+  clang::Stmt *RSClearObjectCall = nullptr;
   if (BaseType->isArrayType()) {
     RSClearObjectCall =
         ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
@@ -579,7 +579,7 @@
       new(C) clang::ForStmt(C,
                             Init,
                             Cond,
-                            NULL,  // no condVar
+                            nullptr,  // no condVar
                             Inc,
                             RSClearObjectCall,
                             Loc,
@@ -667,7 +667,7 @@
   unsigned StmtCount = 0;
   clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
   for (unsigned i = 0; i < FieldsToDestroy; i++) {
-    StmtArray[i] = NULL;
+    StmtArray[i] = nullptr;
   }
 
   // Populate StmtArray by creating a destructor for each RS object field
@@ -700,7 +700,7 @@
                                     FD,
                                     FoundDecl,
                                     clang::DeclarationNameInfo(),
-                                    NULL,
+                                    nullptr,
                                     OrigType->getCanonicalTypeInternal(),
                                     clang::VK_RValue,
                                     clang::OK_Ordinary);
@@ -733,7 +733,7 @@
                                     FD,
                                     FoundDecl,
                                     clang::DeclarationNameInfo(),
-                                    NULL,
+                                    nullptr,
                                     OrigType->getCanonicalTypeInternal(),
                                     clang::VK_RValue,
                                     clang::OK_Ordinary);
@@ -770,7 +770,7 @@
                                             clang::SourceLocation Loc) {
   const clang::Type *T = DstExpr->getType().getTypePtr();
   clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
-  slangAssert((SetObjectFD != NULL) &&
+  slangAssert((SetObjectFD != nullptr) &&
               "rsSetObject doesn't cover all RS object types");
 
   clang::QualType SetObjectFDType = SetObjectFD->getType();
@@ -787,14 +787,14 @@
                                  Loc,
                                  SetObjectFDType,
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   clang::Expr *RSSetObjectFP =
       clang::ImplicitCastExpr::Create(C,
                                       C.getPointerType(SetObjectFDType),
                                       clang::CK_FunctionToPointerDecay,
                                       RefRSSetObjectFD,
-                                      NULL,
+                                      nullptr,
                                       clang::VK_RValue);
 
   llvm::SmallVector<clang::Expr*, 2> ArgList;
@@ -828,7 +828,7 @@
                                            clang::Expr *SrcArr,
                                            clang::SourceLocation StartLoc,
                                            clang::SourceLocation Loc) {
-  clang::DeclContext *DC = NULL;
+  clang::DeclContext *DC = nullptr;
   const clang::Type *BaseType = DstArr->getType().getTypePtr();
   slangAssert(BaseType->isArrayType());
 
@@ -836,11 +836,11 @@
   // Actually extract out the base RS object type for use later
   BaseType = BaseType->getArrayElementTypeNoTypeQual();
 
-  clang::Stmt *StmtArray[2] = {NULL};
+  clang::Stmt *StmtArray[2] = {nullptr};
   int StmtCtr = 0;
 
   if (NumArrayElements <= 0) {
-    return NULL;
+    return nullptr;
   }
 
   // Create helper variable for iterating through elements
@@ -872,7 +872,7 @@
                                  Loc,
                                  C.IntTy,
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
       llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
@@ -916,7 +916,7 @@
           C.getPointerType(BaseType->getCanonicalTypeInternal()),
           clang::CK_ArrayToPointerDecay,
           DstArr,
-          NULL,
+          nullptr,
           clang::VK_RValue);
 
   clang::Expr *DstArrPtrSubscript =
@@ -932,7 +932,7 @@
           C.getPointerType(BaseType->getCanonicalTypeInternal()),
           clang::CK_ArrayToPointerDecay,
           SrcArr,
-          NULL,
+          nullptr,
           clang::VK_RValue);
 
   clang::Expr *SrcArrPtrSubscript =
@@ -945,7 +945,7 @@
 
   DataType DT = RSExportPrimitiveType::GetRSSpecificType(BaseType);
 
-  clang::Stmt *RSSetObjectCall = NULL;
+  clang::Stmt *RSSetObjectCall = nullptr;
   if (BaseType->isArrayType()) {
     RSSetObjectCall = CreateArrayRSSetObject(C, DstArrPtrSubscript,
                                              SrcArrPtrSubscript,
@@ -964,7 +964,7 @@
       new(C) clang::ForStmt(C,
                             Init,
                             Cond,
-                            NULL,  // no condVar
+                            nullptr,  // no condVar
                             Inc,
                             RSSetObjectCall,
                             Loc,
@@ -996,7 +996,7 @@
   unsigned StmtCount = 0;
   clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
   for (unsigned i = 0; i < FieldsToSet; i++) {
-    StmtArray[i] = NULL;
+    StmtArray[i] = nullptr;
   }
 
   clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
@@ -1026,7 +1026,7 @@
                                   FD,
                                   FoundDecl,
                                   clang::DeclarationNameInfo(),
-                                  NULL,
+                                  nullptr,
                                   OrigType->getCanonicalTypeInternal(),
                                   clang::VK_RValue,
                                   clang::OK_Ordinary);
@@ -1040,7 +1040,7 @@
                                   FD,
                                   FoundDecl,
                                   clang::DeclarationNameInfo(),
-                                  NULL,
+                                  nullptr,
                                   OrigType->getCanonicalTypeInternal(),
                                   clang::VK_RValue,
                                   clang::OK_Ordinary);
@@ -1104,7 +1104,7 @@
 
   clang::SourceLocation Loc = AS->getExprLoc();
   clang::SourceLocation StartLoc = AS->getLHS()->getExprLoc();
-  clang::Stmt *UpdatedStmt = NULL;
+  clang::Stmt *UpdatedStmt = nullptr;
 
   if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
     // By definition, this is a struct assignment if we get here
@@ -1148,7 +1148,7 @@
                                    Loc,
                                    T->getCanonicalTypeInternal(),
                                    clang::VK_RValue,
-                                   NULL);
+                                   nullptr);
 
     clang::Stmt *RSSetObjectOps =
         CreateStructRSSetObject(C, RefRSVar, InitExpr, StartLoc, Loc);
@@ -1160,7 +1160,7 @@
   }
 
   clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
-  slangAssert((SetObjectFD != NULL) &&
+  slangAssert((SetObjectFD != nullptr) &&
               "rsSetObject doesn't cover all RS object types");
 
   clang::QualType SetObjectFDType = SetObjectFD->getType();
@@ -1177,14 +1177,14 @@
                                  Loc,
                                  SetObjectFDType,
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   clang::Expr *RSSetObjectFP =
       clang::ImplicitCastExpr::Create(C,
                                       C.getPointerType(SetObjectFDType),
                                       clang::CK_FunctionToPointerDecay,
                                       RefRSSetObjectFD,
-                                      NULL,
+                                      nullptr,
                                       clang::VK_RValue);
 
   const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
@@ -1197,7 +1197,7 @@
                                  Loc,
                                  T->getCanonicalTypeInternal(),
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   llvm::SmallVector<clang::Expr*, 2> ArgList;
   ArgList.push_back(new(C) clang::UnaryOperator(RefRSVar,
@@ -1258,7 +1258,7 @@
                                  Loc,
                                  T->getCanonicalTypeInternal(),
                                  clang::VK_RValue,
-                                 NULL);
+                                 nullptr);
 
   if (T->isArrayType()) {
     return ClearArrayRSObject(C, DC, RefRSVar, StartLoc, Loc);
@@ -1330,7 +1330,7 @@
     DataType DT,
     clang::ASTContext &C,
     const clang::SourceLocation &Loc) {
-  clang::Expr *Res = NULL;
+  clang::Expr *Res = nullptr;
   switch (DT) {
     case DataTypeIsStruct:
     case DataTypeRSElement:
@@ -1354,7 +1354,7 @@
                                           C.NullPtrTy,
                                           clang::CK_IntegralToPointer,
                                           Int0,
-                                          NULL,
+                                          nullptr,
                                           clang::VK_RValue);
 
       llvm::SmallVector<clang::Expr*, 1>InitList;
@@ -1441,7 +1441,7 @@
     if (D->getKind() == clang::Decl::Var) {
       clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
       DataType DT = DataTypeUnknown;
-      clang::Expr *InitExpr = NULL;
+      clang::Expr *InitExpr = nullptr;
       if (InitializeRSObject(VD, &DT, &InitExpr)) {
         // We need to zero-init all RS object types (including matrices), ...
         getCurrentScope()->AppendRSObjectInit(VD, DS, DT, InitExpr);
@@ -1505,7 +1505,7 @@
   clang::FunctionProtoType::ExtProtoInfo EPI;
   clang::QualType T = mCtx.getFunctionType(mCtx.VoidTy,
       llvm::ArrayRef<clang::QualType>(), EPI);
-  clang::FunctionDecl *FD = NULL;
+  clang::FunctionDecl *FD = nullptr;
 
   // Generate rsClearObject() call chains for every global variable
   // (whether static or extern).
@@ -1517,7 +1517,7 @@
       if (CountRSObjectTypes(mCtx, VD->getType().getTypePtr(), loc)) {
         if (!FD) {
           // Only create FD if we are going to use it.
-          FD = clang::FunctionDecl::Create(mCtx, DC, loc, loc, N, T, NULL,
+          FD = clang::FunctionDecl::Create(mCtx, DC, loc, loc, N, T, nullptr,
                                            clang::SC_None);
         }
         // Make sure to create any helpers within the function's DeclContext,
@@ -1530,7 +1530,7 @@
 
   // Nothing needs to be destroyed, so don't emit a dtor.
   if (StmtList.empty()) {
-    return NULL;
+    return nullptr;
   }
 
   clang::CompoundStmt *CS = BuildCompoundStmt(mCtx, StmtList, loc);
diff --git a/slang_rs_object_ref_count.h b/slang_rs_object_ref_count.h
index ca25891..eb200b8 100644
--- a/slang_rs_object_ref_count.h
+++ b/slang_rs_object_ref_count.h
@@ -118,7 +118,7 @@
       return RSSetObjectFD[DT];
     } else {
       slangAssert(false && "incorrect type");
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -132,7 +132,7 @@
       return RSClearObjectFD[DT];
     } else {
       slangAssert(false && "incorrect type");
-      return NULL;
+      return nullptr;
     }
   }
 
diff --git a/slang_rs_reflect_utils.cpp b/slang_rs_reflect_utils.cpp
index 66facab..c67a1a8 100644
--- a/slang_rs_reflect_utils.cpp
+++ b/slang_rs_reflect_utils.cpp
@@ -22,10 +22,11 @@
 #include <iomanip>
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 
 #include "os_sep.h"
 #include "slang_assert.h"
-#include "slang_utils.h"
 
 namespace slang {
 
@@ -169,7 +170,7 @@
   }
 
   FILE *pfin = fopen(filename.c_str(), "rb");
-  if (pfin == NULL) {
+  if (pfin == nullptr) {
     fprintf(stderr, "Error: could not read file %s\n", filename.c_str());
     return false;
   }
@@ -261,9 +262,10 @@
     const BitCodeAccessorContext &context) {
   string output_path =
       ComputePackagedPath(context.reflectPath, context.packageName);
-  if (!SlangUtils::CreateDirectoryWithParents(llvm::StringRef(output_path),
-                                              NULL)) {
-    fprintf(stderr, "Error: could not create dir %s\n", output_path.c_str());
+  if (std::error_code EC = llvm::sys::fs::create_directories(
+          llvm::sys::path::parent_path(output_path))) {
+    fprintf(stderr, "Error: could not create dir %s: %s\n",
+            output_path.c_str(), EC.message().c_str());
     return false;
   }
 
@@ -348,9 +350,9 @@
 
   // Create the parent directories.
   if (!outDirectory.empty()) {
-    std::string errorMsg;
-    if (!SlangUtils::CreateDirectoryWithParents(outDirectory, &errorMsg)) {
-      fprintf(stderr, "Error: %s\n", errorMsg.c_str());
+    if (std::error_code EC = llvm::sys::fs::create_directories(
+            llvm::sys::path::parent_path(outDirectory))) {
+      fprintf(stderr, "Error: %s\n", EC.message().c_str());
       return false;
     }
   }
@@ -365,7 +367,7 @@
   }
 
   // Write the license.
-  if (optionalLicense != NULL) {
+  if (optionalLicense != nullptr) {
     *this << *optionalLicense;
   } else {
     *this << gApacheLicenseNote;
diff --git a/slang_rs_reflect_utils.h b/slang_rs_reflect_utils.h
index dc6b50c..1cbc098 100644
--- a/slang_rs_reflect_utils.h
+++ b/slang_rs_reflect_utils.h
@@ -111,7 +111,7 @@
    * - opening the stream,
    * - writing out the license,
    * - writing a message that this file has been auto-generated.
-   * If optionalLicense is NULL, a default license is used.
+   * If optionalLicense is nullptr, a default license is used.
    */
   bool startFile(const std::string &outPath, const std::string &outFileName,
                  const std::string &sourceFileName,
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index 9f5ccd0..dfa6e75 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -37,7 +37,6 @@
 #include "slang_rs_export_func.h"
 #include "slang_rs_reflect_utils.h"
 #include "slang_version.h"
-#include "slang_utils.h"
 
 #define RS_SCRIPT_CLASS_NAME_PREFIX "ScriptC_"
 #define RS_SCRIPT_CLASS_SUPER_CLASS_NAME "ScriptC"
@@ -115,7 +114,7 @@
     return MatrixTypeJavaNameMap[EMT->getDim() - 2];
 
   slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
-  return NULL;
+  return nullptr;
 }
 
 static const char *GetVectorAccessor(unsigned Index) {
@@ -170,7 +169,7 @@
     return PrimitiveTypePackerAPINameMap[EPT->getType()];
 
   slangAssert(false && "GetPackerAPIName : Unknown primitive data type");
-  return NULL;
+  return nullptr;
 }
 
 static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) {
@@ -358,7 +357,7 @@
   // Generate a simple constructor with only a single parameter (the rest
   // can be inferred from information we already have).
   mOut.indent() << "// Constructor\n";
-  startFunction(AM_Public, false, NULL, getClassName(), 1, "RenderScript",
+  startFunction(AM_Public, false, nullptr, getClassName(), 1, "RenderScript",
                 "rs");
 
   if (getEmbedBitcodeInJava()) {
@@ -380,7 +379,7 @@
     endFunction();
 
     // Alternate constructor (legacy) with 3 original parameters.
-    startFunction(AM_Public, false, NULL, getClassName(), 3, "RenderScript",
+    startFunction(AM_Public, false, nullptr, getClassName(), 3, "RenderScript",
                   "rs", "Resources", "resources", "int", "id");
     // Call constructor of super class
     mOut.indent() << "super(rs, resources, id);\n";
@@ -425,7 +424,7 @@
     for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
          BI != EI; BI++) {
 
-      if (*BI != NULL) {
+      if (*BI != nullptr) {
         genTypeInstanceFromPointer(*BI);
       }
     }
@@ -626,6 +625,16 @@
     }
   }
 
+  if (mRSContext->getTargetAPI() >= SLANG_DEVELOPMENT_TARGET_API) {
+    startFunction(AM_Public, false, "Script.InvokeID",
+                  "getInvokeID_" + EF->getName(), 0);
+
+    mOut.indent() << "return createInvokeID(" << RS_EXPORT_FUNC_INDEX_PREFIX
+                  << EF->getName() << ");\n";
+
+    endFunction();
+  }
+
   startFunction(AM_Public, false, "void",
                 "invoke_" + EF->getName(/*Mangle=*/false),
                 // We are using un-mangled name since Java
@@ -640,7 +649,7 @@
     std::string FieldPackerName = EF->getName() + "_fp";
 
     if (genCreateFieldPacker(ERT, FieldPackerName.c_str()))
-      genPackVarOfType(ERT, NULL, FieldPackerName.c_str());
+      genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
 
     mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName()
                   << ", " << FieldPackerName << ");\n";
@@ -764,7 +773,7 @@
   startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args);
 
   if (InTypes.size() == 1) {
-    if (InTypes.front() != NULL) {
+    if (InTypes.front() != nullptr) {
       genTypeCheck(InTypes.front(), "ain");
     }
 
@@ -773,7 +782,7 @@
     for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
          BI != EI; BI++, ++Index) {
 
-      if (*BI != NULL) {
+      if (*BI != nullptr) {
         genTypeCheck(*BI, ("ain_" + Ins[Index]->getName()).str().c_str());
       }
     }
@@ -804,7 +813,7 @@
   std::string FieldPackerName = EF->getName() + "_fp";
   if (ERT) {
     if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
-      genPackVarOfType(ERT, NULL, FieldPackerName.c_str());
+      genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
     }
   }
   mOut.indent() << "forEach(" << RS_EXPORT_FOREACH_INDEX_PREFIX
@@ -1291,7 +1300,7 @@
       size_t FieldStoreSize = T->getStoreSize();
       size_t FieldAllocSize = T->getAllocSize();
 
-      if (VarName != NULL)
+      if (VarName != nullptr)
         FieldName = VarName + ("." + F->getName());
       else
         FieldName = F->getName();
@@ -1376,7 +1385,7 @@
   mOut.indent() << "if (" << RS_TYPE_ITEM_BUFFER_NAME " == null) ";
   mOut << RS_TYPE_ITEM_BUFFER_NAME << " = new " << RS_TYPE_ITEM_CLASS_NAME
        << "[getType().getX() /* count */];\n";
-  if (Index != NULL) {
+  if (Index != nullptr) {
     mOut.indent() << "if (" << RS_TYPE_ITEM_BUFFER_NAME << "[" << Index
                   << "] == null) ";
     mOut << RS_TYPE_ITEM_BUFFER_NAME << "[" << Index << "] = new "
@@ -1495,7 +1504,7 @@
   endFunction();
 
   // private with element
-  startFunction(AM_Private, false, NULL, getClassName(), 1, "RenderScript",
+  startFunction(AM_Private, false, nullptr, getClassName(), 1, "RenderScript",
                 RenderScriptVar);
   mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << " = null;\n";
   mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << " = null;\n";
@@ -1503,7 +1512,7 @@
   endFunction();
 
   // 1D without usage
-  startFunction(AM_Public, false, NULL, getClassName(), 2, "RenderScript",
+  startFunction(AM_Public, false, nullptr, getClassName(), 2, "RenderScript",
                 RenderScriptVar, "int", "count");
 
   mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << " = null;\n";
@@ -1514,7 +1523,7 @@
   endFunction();
 
   // 1D with usage
-  startFunction(AM_Public, false, NULL, getClassName(), 3, "RenderScript",
+  startFunction(AM_Public, false, nullptr, getClassName(), 3, "RenderScript",
                 RenderScriptVar, "int", "count", "int", "usages");
 
   mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << " = null;\n";
@@ -1615,7 +1624,7 @@
   startFunction(AM_PublicSynchronized, false, "void", "set", 3,
                 RS_TYPE_ITEM_CLASS_NAME, "i", "int", "index", "boolean",
                 "copyNow");
-  genNewItemBufferIfNull(NULL);
+  genNewItemBufferIfNull(nullptr);
   mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << "[index] = i;\n";
 
   mOut.indent() << "if (copyNow) ";
@@ -2025,7 +2034,7 @@
 
   mOut << AccessModifierStr(AM) << ((IsStatic) ? " static" : "") << " class "
        << ClassName;
-  if (SuperClassName != NULL)
+  if (SuperClassName != nullptr)
     mOut << " extends " << SuperClassName;
 
   mOut.startBlock();
diff --git a/slang_rs_reflection.h b/slang_rs_reflection.h
index 0c2b773..097a380 100644
--- a/slang_rs_reflection.h
+++ b/slang_rs_reflection.h
@@ -247,7 +247,7 @@
 
   inline const char *getLastError() const {
     if (mLastError.empty())
-      return NULL;
+      return nullptr;
     else
       return mLastError.c_str();
   }
diff --git a/slang_rs_reflection_cpp.cpp b/slang_rs_reflection_cpp.cpp
index 0840d37..ee1b4bc 100644
--- a/slang_rs_reflection_cpp.cpp
+++ b/slang_rs_reflection_cpp.cpp
@@ -34,7 +34,6 @@
 #include "slang_rs_export_func.h"
 #include "slang_rs_reflect_utils.h"
 #include "slang_version.h"
-#include "slang_utils.h"
 
 #include "slang_rs_reflection_cpp.h"
 
@@ -56,7 +55,7 @@
     return MatrixTypeCNameMap[EMT->getDim() - 2];
 
   slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
-  return NULL;
+  return nullptr;
 }
 
 static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) {
@@ -304,7 +303,7 @@
 
 bool RSReflectionCpp::genEncodedBitCode() {
   FILE *pfin = fopen(mBitCodeFilePath.c_str(), "rb");
-  if (pfin == NULL) {
+  if (pfin == nullptr) {
     fprintf(stderr, "Error: could not read file %s\n",
             mBitCodeFilePath.c_str());
     return false;
@@ -431,7 +430,7 @@
     std::string FieldPackerName = ef->getName() + "_fp";
     if (ERT) {
       if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
-        genPackVarOfType(ERT, NULL, FieldPackerName.c_str());
+        genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
       }
     }
     mOut.indent() << "forEach(" << slot << ", ";
@@ -470,7 +469,7 @@
     if (params) {
       param_len = params->getAllocSize();
       if (genCreateFieldPacker(params, "__fp")) {
-        genPackVarOfType(params, NULL, "__fp");
+        genPackVarOfType(params, nullptr, "__fp");
       }
     }
 
@@ -605,7 +604,7 @@
 
 void RSReflectionCpp::genGetterAndSetter(const RSExportVectorType *EVT,
                                          const RSExportVar *EV) {
-  slangAssert(EVT != NULL);
+  slangAssert(EVT != nullptr);
 
   RSReflectionTypeData rtd;
   EVT->convertToRTD(&rtd);
@@ -767,7 +766,7 @@
       size_t FieldStoreSize = T->getStoreSize();
       size_t FieldAllocSize = T->getAllocSize();
 
-      if (VarName != NULL)
+      if (VarName != nullptr)
         FieldName = VarName + ("." + F->getName());
       else
         FieldName = F->getName();
diff --git a/slang_utils.cpp b/slang_utils.cpp
deleted file mode 100644
index 45d1b93..0000000
--- a/slang_utils.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "slang_utils.h"
-
-#include <string>
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/FileSystem.h"
-
-namespace slang {
-
-bool SlangUtils::CreateDirectoryWithParents(llvm::StringRef Dir,
-                                            std::string* Error) {
-  std::error_code EC = llvm::sys::fs::create_directories(Dir);
-  if (EC) {
-    Error->assign(EC.message());
-    return false;
-  }
-  return true;
-}
-
-}  // namespace slang
diff --git a/slang_utils.h b/slang_utils.h
deleted file mode 100644
index 9a123e3..0000000
--- a/slang_utils.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _COMPILE_SLANG_SLANG_UTILS_H_  // NOLINT
-#define _COMPILE_SLANG_SLANG_UTILS_H_
-
-#include <string>
-
-namespace llvm {
-  class StringRef;
-}
-
-namespace slang {
-
-class SlangUtils {
- private:
-  SlangUtils() {}
-
- public:
-  static bool CreateDirectoryWithParents(llvm::StringRef Dir,
-                                         std::string* Error);
-};
-}  // namespace slang
-
-#endif  // _COMPILE_SLANG_SLANG_UTILS_H_  NOLINT
diff --git a/slang_version.h b/slang_version.h
index b11d185..f3b59a7 100644
--- a/slang_version.h
+++ b/slang_version.h
@@ -38,6 +38,7 @@
   SLANG_JB_MR1_TARGET_API = 17,
   SLANG_JB_MR2_TARGET_API = 18,
   SLANG_KK_TARGET_API = 19,
+  SLANG_23_TARGET_API = 23,
   SLANG_MAXIMUM_TARGET_API = RS_VERSION,
   SLANG_DEVELOPMENT_TARGET_API = RS_DEVELOPMENT_API
 };
diff --git a/tests/F_ctxt_wrong_api/F_ctxt_wrong_api.rs b/tests/F_ctxt_wrong_api/F_ctxt_wrong_api.rs
new file mode 100644
index 0000000..34a0a7c
--- /dev/null
+++ b/tests/F_ctxt_wrong_api/F_ctxt_wrong_api.rs
@@ -0,0 +1,7 @@
+// -target-api 22
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL good(int in, rs_kernel_context ctxt) {
+  return 0;
+}
diff --git a/tests/F_ctxt_wrong_api/stderr.txt.expect b/tests/F_ctxt_wrong_api/stderr.txt.expect
new file mode 100644
index 0000000..74d70f7
--- /dev/null
+++ b/tests/F_ctxt_wrong_api/stderr.txt.expect
@@ -0,0 +1 @@
+F_ctxt_wrong_api.rs:5:28: error: unknown type name 'rs_kernel_context'
diff --git a/tests/F_ctxt_wrong_api/stdout.txt.expect b/tests/F_ctxt_wrong_api/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_ctxt_wrong_api/stdout.txt.expect
diff --git a/tests/F_ctxt_wrong_place/F_ctxt_wrong_place.rs b/tests/F_ctxt_wrong_place/F_ctxt_wrong_place.rs
new file mode 100644
index 0000000..7226094
--- /dev/null
+++ b/tests/F_ctxt_wrong_place/F_ctxt_wrong_place.rs
@@ -0,0 +1,11 @@
+// -target-api 23
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL good(int in, rs_kernel_context ctxt, uint32_t x) {
+  return 0;
+}
+
+int RS_KERNEL bad(int in, uint32_t x, rs_kernel_context ctxt) {
+  return 0;
+}
diff --git a/tests/F_ctxt_wrong_place/stderr.txt.expect b/tests/F_ctxt_wrong_place/stderr.txt.expect
new file mode 100644
index 0000000..60c2b70
--- /dev/null
+++ b/tests/F_ctxt_wrong_place/stderr.txt.expect
@@ -0,0 +1 @@
+F_ctxt_wrong_place.rs:9:57: error: In compute kernel bad(), parameter 'ctxt' must be defined before parameter 'x'.
diff --git a/tests/F_ctxt_wrong_place/stdout.txt.expect b/tests/F_ctxt_wrong_place/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_ctxt_wrong_place/stdout.txt.expect
diff --git a/tests/F_ctxt_wrong_type/F_ctxt_wrong_type.rs b/tests/F_ctxt_wrong_type/F_ctxt_wrong_type.rs
new file mode 100644
index 0000000..358dae4
--- /dev/null
+++ b/tests/F_ctxt_wrong_type/F_ctxt_wrong_type.rs
@@ -0,0 +1,15 @@
+// -target-api 23
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL good1(int in, rs_kernel_context ctxt) {
+  return 0;
+}
+
+int RS_KERNEL good2(int in, const rs_kernel_context ctxt) {
+  return 0;
+}
+
+int RS_KERNEL bad3(int in, const rs_kernel_context *ctxt) {
+  return 0;
+}
diff --git a/tests/F_ctxt_wrong_type/stderr.txt.expect b/tests/F_ctxt_wrong_type/stderr.txt.expect
new file mode 100644
index 0000000..54cf641
--- /dev/null
+++ b/tests/F_ctxt_wrong_type/stderr.txt.expect
@@ -0,0 +1 @@
+F_ctxt_wrong_type.rs:13:53: error: Parameter 'ctxt' must be of type 'rs_kernel_context'. It is of type 'const rs_kernel_context *'.
diff --git a/tests/F_ctxt_wrong_type/stdout.txt.expect b/tests/F_ctxt_wrong_type/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_ctxt_wrong_type/stdout.txt.expect
diff --git a/tests/F_incompatible_handles/incompatible_handles.rs b/tests/F_incompatible_handles/incompatible_handles.rs
new file mode 100644
index 0000000..e7ff6c2
--- /dev/null
+++ b/tests/F_incompatible_handles/incompatible_handles.rs
@@ -0,0 +1,8 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void foo() {
+  rs_allocation a;
+  rs_mesh m;
+  a = m;
+}
diff --git a/tests/F_incompatible_handles/stderr.txt.expect b/tests/F_incompatible_handles/stderr.txt.expect
new file mode 100644
index 0000000..64759c6
--- /dev/null
+++ b/tests/F_incompatible_handles/stderr.txt.expect
@@ -0,0 +1 @@
+incompatible_handles.rs:7:5: error: assigning to 'rs_allocation' from incompatible type 'rs_mesh'
diff --git a/tests/F_incompatible_handles/stdout.txt.expect b/tests/F_incompatible_handles/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_incompatible_handles/stdout.txt.expect
diff --git a/tests/F_multi_in_target_version/stderr.txt.expect b/tests/F_multi_in_target_version/stderr.txt.expect
index a9376b5..56eae17 100644
--- a/tests/F_multi_in_target_version/stderr.txt.expect
+++ b/tests/F_multi_in_target_version/stderr.txt.expect
@@ -1 +1 @@
-multi_in_target_version.rs:5:43: error: Invalid parameter 'in1' for compute kernel root(). Kernels targeting SDK levels 11-21 may not use multiple input parameters.
+multi_in_target_version.rs:5:43: error: Invalid parameter 'in1' for compute kernel root(). Kernels targeting SDK levels 11-23 may not use multiple input parameters.
diff --git a/tests/F_root_compute_int_in/stderr.txt.expect b/tests/F_root_compute_int_in/stderr.txt.expect
index 9cd6e25..cf6eabe 100644
--- a/tests/F_root_compute_int_in/stderr.txt.expect
+++ b/tests/F_root_compute_int_in/stderr.txt.expect
@@ -1,2 +1,2 @@
-root_compute_int_in.rs:4:21: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'in' is of type: 'const int'
+root_compute_int_in.rs:4:21: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'in' is of type: 'const int'
 root_compute_int_in.rs:4:6: error: Compute kernel root() must have at least one parameter for in or out
diff --git a/tests/F_root_compute_non_ptr_usrData/stderr.txt.expect b/tests/F_root_compute_non_ptr_usrData/stderr.txt.expect
index 835e708..04c7735 100644
--- a/tests/F_root_compute_non_ptr_usrData/stderr.txt.expect
+++ b/tests/F_root_compute_non_ptr_usrData/stderr.txt.expect
@@ -1 +1 @@
-root_compute_non_ptr_usrData.rs:4:48: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'usrData' is of type: 'const int'
+root_compute_non_ptr_usrData.rs:4:48: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'usrData' is of type: 'const int'
diff --git a/tests/F_root_compute_non_uint32_t_xyzar/stderr.txt.expect b/tests/F_root_compute_non_uint32_t_xyzar/stderr.txt.expect
index 84a150f..ba7eecb 100644
--- a/tests/F_root_compute_non_uint32_t_xyzar/stderr.txt.expect
+++ b/tests/F_root_compute_non_uint32_t_xyzar/stderr.txt.expect
@@ -1,5 +1,6 @@
-root_compute_non_uint32_t_xyzar.rs:5:17: error: Parameter 'x' must be of type 'int' or 'unsigned int'. It is of type 'short'
-root_compute_non_uint32_t_xyzar.rs:5:26: error: Parameter 'y' must be of type 'int' or 'unsigned int'. It is of type 'float'
-root_compute_non_uint32_t_xyzar.rs:5:36: error: In compute kernel root(), parameter 'z' cannot appear after the 'x' and 'y' parameters
-root_compute_non_uint32_t_xyzar.rs:5:45: error: In compute kernel root(), parameter 'ar' cannot appear after the 'x' and 'y' parameters
-root_compute_non_uint32_t_xyzar.rs:5:26: error: Parameter 'x' and 'y' must be of the same type. 'x' is of type 'short' while 'y' is of type 'float'
+root_compute_non_uint32_t_xyzar.rs:5:17: error: Parameter 'x' must be of type 'int' or 'unsigned int'. It is of type 'short'.
+root_compute_non_uint32_t_xyzar.rs:5:26: error: Parameters 'x' and 'y' must be of the same type. 'x' is of type 'short' while 'y' is of type 'float'.
+root_compute_non_uint32_t_xyzar.rs:5:26: error: Parameter 'y' must be of type 'int' or 'unsigned int'. It is of type 'float'.
+root_compute_non_uint32_t_xyzar.rs:5:36: error: Parameters 'x' and 'z' must be of the same type. 'x' is of type 'short' while 'z' is of type 'double'.
+root_compute_non_uint32_t_xyzar.rs:5:36: error: Parameter 'z' must be of type 'int' or 'unsigned int'. It is of type 'double'.
+root_compute_non_uint32_t_xyzar.rs:5:45: error: In compute kernel root(), parameter 'ar' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
diff --git a/tests/F_root_compute_non_uint32_t_xyzwar/root_compute_non_uint32_t_xyzwar.rs b/tests/F_root_compute_non_uint32_t_xyzwar/root_compute_non_uint32_t_xyzwar.rs
new file mode 100644
index 0000000..b3a00ad
--- /dev/null
+++ b/tests/F_root_compute_non_uint32_t_xyzwar/root_compute_non_uint32_t_xyzwar.rs
@@ -0,0 +1,7 @@
+// -target-api 23
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void root(const int *ain, int *aout, const void *usrData,
+          short x, float y, double z, long w, uchar ar) {
+}
diff --git a/tests/F_root_compute_non_uint32_t_xyzwar/stderr.txt.expect b/tests/F_root_compute_non_uint32_t_xyzwar/stderr.txt.expect
new file mode 100644
index 0000000..bdd564b
--- /dev/null
+++ b/tests/F_root_compute_non_uint32_t_xyzwar/stderr.txt.expect
@@ -0,0 +1,7 @@
+root_compute_non_uint32_t_xyzwar.rs:6:17: error: Parameter 'x' must be of type 'int' or 'unsigned int'. It is of type 'short'.
+root_compute_non_uint32_t_xyzwar.rs:6:26: error: Parameters 'x' and 'y' must be of the same type. 'x' is of type 'short' while 'y' is of type 'float'.
+root_compute_non_uint32_t_xyzwar.rs:6:26: error: Parameter 'y' must be of type 'int' or 'unsigned int'. It is of type 'float'.
+root_compute_non_uint32_t_xyzwar.rs:6:36: error: Parameters 'x' and 'z' must be of the same type. 'x' is of type 'short' while 'z' is of type 'double'.
+root_compute_non_uint32_t_xyzwar.rs:6:36: error: Parameter 'z' must be of type 'int' or 'unsigned int'. It is of type 'double'.
+root_compute_non_uint32_t_xyzwar.rs:6:44: error: In compute kernel root(), parameter 'w' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
+root_compute_non_uint32_t_xyzwar.rs:6:53: error: In compute kernel root(), parameter 'ar' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
diff --git a/tests/F_root_compute_non_uint32_t_xyzwar/stdout.txt.expect b/tests/F_root_compute_non_uint32_t_xyzwar/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_root_compute_non_uint32_t_xyzwar/stdout.txt.expect
diff --git a/tests/F_root_compute_really_bad/stderr.txt.expect b/tests/F_root_compute_really_bad/stderr.txt.expect
index ec826f7..8d9589c 100644
--- a/tests/F_root_compute_really_bad/stderr.txt.expect
+++ b/tests/F_root_compute_really_bad/stderr.txt.expect
@@ -1,21 +1,21 @@
 root_compute_really_bad.rs:4:5: error: Compute kernel root() is required to return a void type
-root_compute_really_bad.rs:5:31: error: In compute kernel root(), parameter 'x' should be defined before parameter 'y'
-root_compute_really_bad.rs:6:19: error: In compute kernel root(), parameter 'extra1' cannot appear after the 'x' and 'y' parameters
-root_compute_really_bad.rs:6:36: error: In compute kernel root(), parameter 'extra2' cannot appear after the 'x' and 'y' parameters
-root_compute_really_bad.rs:4:14: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'ain' is of type: 'int'
-root_compute_really_bad.rs:4:23: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'aout' is of type: 'int'
-root_compute_really_bad.rs:4:33: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'usrData' is of type: 'int'
-root_compute_really_bad.rs:4:48: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'x1' is of type: 'float'
-root_compute_really_bad.rs:4:59: error: Compute kernel root() cannot have non-pointer parameters besides 'x' and 'y'. Parameter 'y1' is of type: 'double'
+root_compute_really_bad.rs:5:31: error: In compute kernel root(), parameter 'x' must be defined before parameter 'y'.
+root_compute_really_bad.rs:6:19: error: In compute kernel root(), parameter 'extra1' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
+root_compute_really_bad.rs:6:36: error: In compute kernel root(), parameter 'extra2' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
+root_compute_really_bad.rs:4:14: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'ain' is of type: 'int'
+root_compute_really_bad.rs:4:23: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'aout' is of type: 'int'
+root_compute_really_bad.rs:4:33: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'usrData' is of type: 'int'
+root_compute_really_bad.rs:4:48: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'x1' is of type: 'float'
+root_compute_really_bad.rs:4:59: error: Compute kernel root() cannot have non-pointer parameters besides ('ctxt', 'x', 'y', 'z'). Parameter 'y1' is of type: 'double'
 root_compute_really_bad.rs:4:5: error: Compute kernel root() must have at least one parameter for in or out
 root_compute_really_bad.rs:10:44: error: Compute kernel root2() can only have one non-const pointer parameter. Parameters 'ain' and 'usrData' are both non-const.
 root_compute_really_bad.rs:10:66: error: Unexpected parameter 'x1' for compute kernel root2()
 root_compute_really_bad.rs:11:26: error: Unexpected parameter 'y1' for compute kernel root2()
-root_compute_really_bad.rs:16:38: error: In compute kernel root_kernel(), parameter 'x' should be defined before parameter 'y'
-root_compute_really_bad.rs:16:50: error: In compute kernel root_kernel(), parameter 'extra1' cannot appear after the 'x' and 'y' parameters
-root_compute_really_bad.rs:16:67: error: In compute kernel root_kernel(), parameter 'extra2' cannot appear after the 'x' and 'y' parameters
-root_compute_really_bad.rs:15:31: error: Invalid parameter 'aout' for compute kernel root_kernel(). Kernels targeting SDK levels 11-21 may not use multiple input parameters.
+root_compute_really_bad.rs:16:38: error: In compute kernel root_kernel(), parameter 'x' must be defined before parameter 'y'.
+root_compute_really_bad.rs:16:50: error: In compute kernel root_kernel(), parameter 'extra1' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
+root_compute_really_bad.rs:16:67: error: In compute kernel root_kernel(), parameter 'extra2' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
+root_compute_really_bad.rs:15:31: error: Invalid parameter 'aout' for compute kernel root_kernel(). Kernels targeting SDK levels 11-23 may not use multiple input parameters.
 root_compute_really_bad.rs:15:31: error: Compute kernel root_kernel() cannot have parameter 'aout' of pointer type: 'int *'
-root_compute_really_bad.rs:15:41: error: Invalid parameter 'usrData' for compute kernel root_kernel(). Kernels targeting SDK levels 11-21 may not use multiple input parameters.
-root_compute_really_bad.rs:15:56: error: Invalid parameter 'x1' for compute kernel root_kernel(). Kernels targeting SDK levels 11-21 may not use multiple input parameters.
-root_compute_really_bad.rs:15:67: error: Invalid parameter 'y1' for compute kernel root_kernel(). Kernels targeting SDK levels 11-21 may not use multiple input parameters.
+root_compute_really_bad.rs:15:41: error: Invalid parameter 'usrData' for compute kernel root_kernel(). Kernels targeting SDK levels 11-23 may not use multiple input parameters.
+root_compute_really_bad.rs:15:56: error: Invalid parameter 'x1' for compute kernel root_kernel(). Kernels targeting SDK levels 11-23 may not use multiple input parameters.
+root_compute_really_bad.rs:15:67: error: Invalid parameter 'y1' for compute kernel root_kernel(). Kernels targeting SDK levels 11-23 may not use multiple input parameters.
diff --git a/tests/F_root_compute_too_many_args/stderr.txt.expect b/tests/F_root_compute_too_many_args/stderr.txt.expect
index 56d081b..dbb0500 100644
--- a/tests/F_root_compute_too_many_args/stderr.txt.expect
+++ b/tests/F_root_compute_too_many_args/stderr.txt.expect
@@ -1,2 +1,2 @@
-root_compute_too_many_args.rs:6:20: error: In compute kernel root(), parameter 'extra1' cannot appear after the 'x' and 'y' parameters
-root_compute_too_many_args.rs:6:37: error: In compute kernel root(), parameter 'extra2' cannot appear after the 'x' and 'y' parameters
+root_compute_too_many_args.rs:6:20: error: In compute kernel root(), parameter 'extra1' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
+root_compute_too_many_args.rs:6:37: error: In compute kernel root(), parameter 'extra2' cannot appear after any of the ('ctxt', 'x', 'y', 'z') parameters.
diff --git a/tests/F_set_target_api_10/stderr.txt.expect b/tests/F_set_target_api_10/stderr.txt.expect
index cbe60d0..605ee83 100644
--- a/tests/F_set_target_api_10/stderr.txt.expect
+++ b/tests/F_set_target_api_10/stderr.txt.expect
@@ -1 +1 @@
-error: target API level '10' is out of range ('11' - '21')
+error: target API level '10' is out of range ('11' - '23')
diff --git a/tests/F_set_target_api_9000/stderr.txt.expect b/tests/F_set_target_api_9000/stderr.txt.expect
index 91bb723..b5bcdff 100644
--- a/tests/F_set_target_api_9000/stderr.txt.expect
+++ b/tests/F_set_target_api_9000/stderr.txt.expect
@@ -1 +1 @@
-error: target API level '9000' is out of range ('11' - '21')
+error: target API level '9000' is out of range ('11' - '23')
diff --git a/tests/F_too_many_inputs/F_too_many_inputs.rs b/tests/F_too_many_inputs/F_too_many_inputs.rs
new file mode 100644
index 0000000..248ee4f
--- /dev/null
+++ b/tests/F_too_many_inputs/F_too_many_inputs.rs
@@ -0,0 +1,11 @@
+// -target-api 0
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL good(int in0, int in1, int in2, int in3, int in4, int in5, int in6, int in7) {
+  return 0;
+}
+
+int RS_KERNEL bad(int in0, int in1, int in2, int in3, int in4, int in5, int in6, int in7, int in8) {
+  return 0;
+}
diff --git a/tests/F_too_many_inputs/stderr.txt.expect b/tests/F_too_many_inputs/stderr.txt.expect
new file mode 100644
index 0000000..02e3347
--- /dev/null
+++ b/tests/F_too_many_inputs/stderr.txt.expect
@@ -0,0 +1 @@
+F_too_many_inputs.rs:9:95: error: Invalid parameter 'in8' for compute kernel bad(). Kernels targeting SDK levels 11-23 may not use more than 8 input parameters.
diff --git a/tests/F_too_many_inputs/stdout.txt.expect b/tests/F_too_many_inputs/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_too_many_inputs/stdout.txt.expect
diff --git a/tests/F_z_wrong_api/F_z_wrong_api.rs b/tests/F_z_wrong_api/F_z_wrong_api.rs
new file mode 100644
index 0000000..42b08a2
--- /dev/null
+++ b/tests/F_z_wrong_api/F_z_wrong_api.rs
@@ -0,0 +1,7 @@
+// -target-api 22
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL bad(int in, uint32_t x, uint32_t y, uint32_t z) {
+  return 0;
+}
diff --git a/tests/F_z_wrong_api/stderr.txt.expect b/tests/F_z_wrong_api/stderr.txt.expect
new file mode 100644
index 0000000..9553acd
--- /dev/null
+++ b/tests/F_z_wrong_api/stderr.txt.expect
@@ -0,0 +1 @@
+F_z_wrong_api.rs:5:60: error: Compute kernel bad() targeting SDK levels 11-22 may not use parameter 'z'.
diff --git a/tests/F_z_wrong_api/stdout.txt.expect b/tests/F_z_wrong_api/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_z_wrong_api/stdout.txt.expect
diff --git a/tests/P_warnings_rsSetElementAt/stderr.txt.expect b/tests/P_warnings_rsSetElementAt/stderr.txt.expect
index 71b7aab..d003f5e 100644
--- a/tests/P_warnings_rsSetElementAt/stderr.txt.expect
+++ b/tests/P_warnings_rsSetElementAt/stderr.txt.expect
@@ -10,3 +10,4 @@
 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.
+setelementat.rs:33:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_ulong() instead.