Merge "Adds support for multi-input kernels to Slang."
diff --git a/rs_cc_options.cpp b/rs_cc_options.cpp
index 851e9f6..474250c 100644
--- a/rs_cc_options.cpp
+++ b/rs_cc_options.cpp
@@ -214,5 +214,9 @@
 
     Opts.mTargetAPI = clang::getLastArgIntValue(*Args, OPT_target_api,
                                                 RS_VERSION, DiagEngine);
+
+    if (Opts.mTargetAPI == 0) {
+      Opts.mTargetAPI = UINT_MAX;
+    }
   }
 }
diff --git a/slang_backend.cpp b/slang_backend.cpp
index d011731..43d843e 100644
--- a/slang_backend.cpp
+++ b/slang_backend.cpp
@@ -344,7 +344,7 @@
       llvm::PassManager *BCEmitPM = new llvm::PassManager();
       std::string BCStr;
       llvm::raw_string_ostream Bitcode(BCStr);
-      int TargetAPI = getTargetAPI();
+      unsigned int TargetAPI = getTargetAPI();
       switch (TargetAPI) {
         case SLANG_HC_TARGET_API:
         case SLANG_HC_MR1_TARGET_API:
diff --git a/slang_backend.h b/slang_backend.h
index 834c49a..4254aca 100644
--- a/slang_backend.h
+++ b/slang_backend.h
@@ -81,7 +81,7 @@
 
   PragmaList *mPragmas;
 
-  virtual int getTargetAPI() const {
+  virtual unsigned int getTargetAPI() const {
     return SLANG_MAXIMUM_TARGET_API;
   }
 
diff --git a/slang_rs.h b/slang_rs.h
index f94581e..e878179 100644
--- a/slang_rs.h
+++ b/slang_rs.h
@@ -41,7 +41,7 @@
 
   bool mAllowRSPrefix;
 
-  int mTargetAPI;
+  unsigned int mTargetAPI;
 
   bool mVerbose;
 
diff --git a/slang_rs_backend.h b/slang_rs_backend.h
index 8b449e9..a8fef0e 100644
--- a/slang_rs_backend.h
+++ b/slang_rs_backend.h
@@ -69,7 +69,7 @@
   void dumpExportTypeInfo(llvm::Module *M);
 
  protected:
-  virtual int getTargetAPI() const {
+  virtual unsigned int getTargetAPI() const {
     return mContext->getTargetAPI();
   }
 
diff --git a/slang_rs_context.h b/slang_rs_context.h
index 338bded..3373a8b 100644
--- a/slang_rs_context.h
+++ b/slang_rs_context.h
@@ -67,7 +67,7 @@
   clang::Preprocessor &mPP;
   clang::ASTContext &mCtx;
   PragmaList *mPragmas;
-  int mTargetAPI;
+  unsigned int mTargetAPI;
   bool mVerbose;
 
   llvm::DataLayout *mDataLayout;
@@ -119,7 +119,7 @@
   inline clang::DiagnosticsEngine *getDiagnostics() const {
     return &mPP.getDiagnostics();
   }
-  inline int getTargetAPI() const {
+  inline unsigned int getTargetAPI() const {
     return mTargetAPI;
   }
 
diff --git a/slang_rs_export_foreach.cpp b/slang_rs_export_foreach.cpp
index b9797b4..439f9a9 100644
--- a/slang_rs_export_foreach.cpp
+++ b/slang_rs_export_foreach.cpp
@@ -61,6 +61,7 @@
   } else {
     valid |= validateAndConstructOldStyleParams(Context, FD);
   }
+
   valid |= setSignatureMetadata(Context, FD);
   return valid;
 }
@@ -118,8 +119,8 @@
         valid = false;
       }
     } else {
-      if (mIn == NULL && mOut == NULL) {
-        mIn = PVD;
+      if (mIns.empty() && mOut == NULL) {
+        mIns.push_back(PVD);
       } else if (mUsrData == NULL) {
         mUsrData = PVD;
       } else {
@@ -132,7 +133,7 @@
     }
   }
 
-  if (!mIn && !mOut) {
+  if (mIns.empty() && !mOut) {
     Context->ReportError(FD->getLocation(),
                          "Compute kernel %0() must have at least one "
                          "parameter for in or out")
@@ -181,13 +182,20 @@
   // first iterator.
   for (size_t i = 0; i < IndexOfFirstIterator; i++) {
     const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
-    if (i == 0) {
-      mIn = PVD;
+
+    /*
+     * FIXME: Change this to a test against an actual API version when the
+     *        multi-input feature is officially supported.
+     */
+    if (Context->getTargetAPI() == SLANG_DEVELOPMENT_TARGET_API || i == 0) {
+      mIns.push_back(PVD);
     } else {
       Context->ReportError(PVD->getLocation(),
-                           "Unrecognized parameter '%0'. Compute kernel %1() "
-                           "can only have one input parameter, 'x', and 'y'")
-          << PVD->getName() << FD->getName();
+                           "Invalid parameter '%0' for compute kernel %1(). "
+                           "Kernels targeting SDK levels %2-%3 may not use "
+                           "multiple input parameters.") << PVD->getName() <<
+                           FD->getName() << SLANG_MINIMUM_TARGET_API <<
+                           SLANG_MAXIMUM_TARGET_API;
       valid = false;
     }
     clang::QualType QT = PVD->getType().getCanonicalType();
@@ -201,7 +209,7 @@
   }
 
   // Check that we have at least one allocation to use for dimensions.
-  if (valid && !mIn && !mHasReturnType) {
+  if (valid && mIns.empty() && !mHasReturnType) {
     Context->ReportError(FD->getLocation(),
                          "Compute kernel %0() must have at least one "
                          "input parameter or a non-void return "
@@ -300,7 +308,7 @@
   // 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 |= (mIn ?            0x01 : 0);
+  mSignatureMetadata |= (hasIns() ?       0x01 : 0);
   mSignatureMetadata |= (HasOut ?         0x02 : 0);
   mSignatureMetadata |= (mUsrData ?       0x04 : 0);
   mSignatureMetadata |= (mX ?             0x08 : 0);
@@ -399,11 +407,17 @@
     }
   }
 
-  if (FE->mIn) {
-    const clang::Type *T = FE->mIn->getType().getCanonicalType().getTypePtr();
-    FE->mInType = RSExportType::Create(Context, T);
-    if (FE->mIsKernelStyle) {
-      slangAssert(FE->mInType);
+  if (FE->hasIns()) {
+
+    for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
+      const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
+      RSExportType *InExportType = RSExportType::Create(Context, T);
+
+      if (FE->mIsKernelStyle) {
+        slangAssert(InExportType != NULL);
+      }
+
+      FE->mInTypes.push_back(InExportType);
     }
   }
 
@@ -427,7 +441,7 @@
   return FE;
 }
 
-bool RSExportForEach::isGraphicsRootRSFunc(int targetAPI,
+bool RSExportForEach::isGraphicsRootRSFunc(unsigned int targetAPI,
                                            const clang::FunctionDecl *FD) {
   if (FD->hasAttr<clang::KernelAttr>()) {
     return false;
@@ -453,9 +467,9 @@
   return false;
 }
 
-bool RSExportForEach::isRSForEachFunc(int targetAPI,
-    slang::RSContext* Context,
-    const clang::FunctionDecl *FD) {
+bool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
+                                      slang::RSContext* Context,
+                                      const clang::FunctionDecl *FD) {
   slangAssert(Context && FD);
   bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>();
 
@@ -503,7 +517,7 @@
 }
 
 bool
-RSExportForEach::validateSpecialFuncDecl(int targetAPI,
+RSExportForEach::validateSpecialFuncDecl(unsigned int targetAPI,
                                          slang::RSContext *Context,
                                          clang::FunctionDecl const *FD) {
   slangAssert(Context && FD);
diff --git a/slang_rs_export_foreach.h b/slang_rs_export_foreach.h
index 7172c86..f401d19 100644
--- a/slang_rs_export_foreach.h
+++ b/slang_rs_export_foreach.h
@@ -18,6 +18,7 @@
 #define _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_EXPORT_FOREACH_H_
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include "clang/AST/Decl.h"
@@ -36,16 +37,24 @@
 // Base class for reflecting control-side forEach (currently for root()
 // functions that fit appropriate criteria)
 class RSExportForEach : public RSExportable {
+ public:
+
+  typedef llvm::SmallVectorImpl<const clang::ParmVarDecl*> InVec;
+  typedef llvm::SmallVectorImpl<const RSExportType*> InTypeVec;
+
+  typedef InVec::const_iterator InIter;
+  typedef InTypeVec::const_iterator InTypeIter;
+
  private:
   std::string mName;
   RSExportRecordType *mParamPacketType;
-  RSExportType *mInType;
+  llvm::SmallVector<const RSExportType*, 16> mInTypes;
   RSExportType *mOutType;
   size_t numParams;
 
   unsigned int mSignatureMetadata;
 
-  const clang::ParmVarDecl *mIn;
+  llvm::SmallVector<const clang::ParmVarDecl*, 16> mIns;
   const clang::ParmVarDecl *mOut;
   const clang::ParmVarDecl *mUsrData;
   const clang::ParmVarDecl *mX;
@@ -60,9 +69,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), mInType(NULL),
+      mName(Name.data(), Name.size()), mParamPacketType(NULL),
       mOutType(NULL), numParams(0), mSignatureMetadata(0),
-      mIn(NULL), mOut(NULL), mUsrData(NULL), mX(NULL), mY(NULL),
+      mOut(NULL), mUsrData(NULL), mX(NULL), mY(NULL),
       mResultType(clang::QualType()), mHasReturnType(false),
       mIsKernelStyle(false), mDummyRoot(false) {
   }
@@ -96,8 +105,8 @@
     return numParams;
   }
 
-  inline bool hasIn() const {
-    return (mIn != NULL);
+  inline bool hasIns() const {
+    return (!mIns.empty());
   }
 
   inline bool hasOut() const {
@@ -112,8 +121,12 @@
     return mHasReturnType;
   }
 
-  inline const RSExportType *getInType() const {
-    return mInType;
+  inline const InVec& getIns() const {
+    return mIns;
+  }
+
+  inline const InTypeVec& getInTypes() const {
+    return mInTypes;
   }
 
   inline const RSExportType *getOutType() const {
@@ -173,19 +186,19 @@
     return Name.equals(FuncDtor);
   }
 
-  static bool isGraphicsRootRSFunc(int targetAPI,
+  static bool isGraphicsRootRSFunc(unsigned int targetAPI,
                                    const clang::FunctionDecl *FD);
 
-  static bool isRSForEachFunc(int targetAPI, slang::RSContext *Context,
+  static bool isRSForEachFunc(unsigned int targetAPI, slang::RSContext *Context,
                               const clang::FunctionDecl *FD);
 
-  inline static bool isSpecialRSFunc(int targetAPI,
+  inline static bool isSpecialRSFunc(unsigned int targetAPI,
                                      const clang::FunctionDecl *FD) {
     return isGraphicsRootRSFunc(targetAPI, FD) || isInitRSFunc(FD) ||
            isDtorRSFunc(FD);
   }
 
-  static bool validateSpecialFuncDecl(int targetAPI,
+  static bool validateSpecialFuncDecl(unsigned int targetAPI,
                                       slang::RSContext *Context,
                                       const clang::FunctionDecl *FD);
 };  // RSExportForEach
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index 6f7a3b6..dcf8422 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -423,10 +423,15 @@
        I != E; I++) {
     const RSExportForEach *EF = *I;
 
-    const RSExportType *IET = EF->getInType();
-    if (IET) {
-      genTypeInstanceFromPointer(IET);
+    const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
+    for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
+         BI != EI; BI++) {
+
+      if (*BI != NULL) {
+        genTypeInstanceFromPointer(*BI);
+      }
     }
+
     const RSExportType *OET = EF->getOutType();
     if (OET) {
       genTypeInstanceFromPointer(OET);
@@ -646,6 +651,24 @@
   endFunction();
 }
 
+void RSReflectionJava::genPairwiseDimCheck(std::string name0,
+                                           std::string name1) {
+
+  mOut.indent() << "// Verify dimensions\n";
+  mOut.indent() << "t0 = " << name0 << ".getType();\n";
+  mOut.indent() << "t1 = " << name1 << ".getType();\n";
+  mOut.indent() << "if ((t0.getCount() != t1.getCount()) ||\n";
+  mOut.indent() << "    (t0.getX() != t1.getX()) ||\n";
+  mOut.indent() << "    (t0.getY() != t1.getY()) ||\n";
+  mOut.indent() << "    (t0.getZ() != t1.getZ()) ||\n";
+  mOut.indent() << "    (t0.hasFaces()   != t1.hasFaces()) ||\n";
+  mOut.indent() << "    (t0.hasMipmaps() != t1.hasMipmaps())) {\n";
+  mOut.indent() << "    throw new RSRuntimeException(\"Dimension mismatch "
+                << "between parameters " << name0 << " and " << name1
+                << "!\");\n";
+  mOut.indent() << "}\n\n";
+}
+
 void RSReflectionJava::genExportForEach(const RSExportForEach *EF) {
   if (EF->isDummyRoot()) {
     // Skip reflection for dummy root() kernels. Note that we have to
@@ -665,8 +688,22 @@
 
   slangAssert(EF->getNumParameters() > 0 || EF->hasReturn());
 
-  if (EF->hasIn())
+  const RSExportForEach::InVec     &Ins     = EF->getIns();
+  const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
+  const RSExportType               *OET     = EF->getOutType();
+
+  if (Ins.size() == 1) {
     Args.push_back(std::make_pair("Allocation", "ain"));
+
+  } else if (Ins.size() > 1) {
+    for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI;
+         BI++) {
+
+      Args.push_back(std::make_pair("Allocation",
+                                    "ain_" + (*BI)->getName().str()));
+    }
+  }
+
   if (EF->hasOut() || EF->hasReturn())
     Args.push_back(std::make_pair("Allocation", "aout"));
 
@@ -680,22 +717,14 @@
     }
   }
 
-  const RSExportType *IET = EF->getInType();
-  const RSExportType *OET = EF->getOutType();
-
   if (mRSContext->getTargetAPI() >= SLANG_JB_MR1_TARGET_API) {
-    int signature = 0;
     startFunction(AM_Public, false, "Script.KernelID",
                   "getKernelID_" + EF->getName(), 0);
 
-    if (IET)
-      signature |= 1;
-    if (OET)
-      signature |= 2;
-
     // TODO: add element checking
     mOut.indent() << "return createKernelID(" << RS_EXPORT_FOREACH_INDEX_PREFIX
-                  << EF->getName() << ", " << signature << ", null, null);\n";
+                  << EF->getName() << ", " << EF->getSignatureMetadata()
+                  << ", null, null);\n";
 
     endFunction();
   }
@@ -706,8 +735,15 @@
     mOut.indent() << "forEach_" << EF->getName();
     mOut << "(";
 
-    if (EF->hasIn()) {
+    if (Ins.size() == 1) {
       mOut << "ain, ";
+
+    } else if (Ins.size() > 1) {
+      for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI;
+           BI++) {
+
+        mOut << "ain_" << (*BI)->getName().str() << ", ";
+      }
     }
 
     if (EF->hasOut() || EF->hasReturn()) {
@@ -729,26 +765,42 @@
 
   startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args);
 
-  if (IET) {
-    genTypeCheck(IET, "ain");
+  if (InTypes.size() == 1) {
+    if (InTypes.front() != NULL) {
+      genTypeCheck(InTypes.front(), "ain");
+    }
+
+  } else if (InTypes.size() > 1) {
+    size_t Index = 0;
+    for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
+         BI != EI; BI++, ++Index) {
+
+      if (*BI != NULL) {
+        genTypeCheck(*BI, ("ain_" + Ins[Index]->getName()).str().c_str());
+      }
+    }
   }
+
   if (OET) {
     genTypeCheck(OET, "aout");
   }
 
-  if (EF->hasIn() && (EF->hasOut() || EF->hasReturn())) {
-    mOut.indent() << "// Verify dimensions\n";
-    mOut.indent() << "Type tIn = ain.getType();\n";
-    mOut.indent() << "Type tOut = aout.getType();\n";
-    mOut.indent() << "if ((tIn.getCount() != tOut.getCount()) ||\n";
-    mOut.indent() << "    (tIn.getX() != tOut.getX()) ||\n";
-    mOut.indent() << "    (tIn.getY() != tOut.getY()) ||\n";
-    mOut.indent() << "    (tIn.getZ() != tOut.getZ()) ||\n";
-    mOut.indent() << "    (tIn.hasFaces() != tOut.hasFaces()) ||\n";
-    mOut.indent() << "    (tIn.hasMipmaps() != tOut.hasMipmaps())) {\n";
-    mOut.indent() << "    throw new RSRuntimeException(\"Dimension mismatch "
-                  << "between input and output parameters!\");\n";
-    mOut.indent() << "}\n";
+  if (Ins.size() == 1 && (EF->hasOut() || EF->hasReturn())) {
+    mOut.indent() << "Type t0, t1;";
+    genPairwiseDimCheck("ain", "aout");
+
+  } else if (Ins.size() > 1) {
+    mOut.indent() << "Type t0, t1;";
+
+    std::string In0Name = "ain_" + Ins[0]->getName().str();
+
+    for (size_t index = 1; index < Ins.size(); ++index) {
+      genPairwiseDimCheck(In0Name, "ain_" + Ins[index]->getName().str());
+    }
+
+    if (EF->hasOut() || EF->hasReturn()) {
+      genPairwiseDimCheck(In0Name, "aout");
+    }
   }
 
   std::string FieldPackerName = EF->getName() + "_fp";
@@ -760,10 +812,20 @@
   mOut.indent() << "forEach(" << RS_EXPORT_FOREACH_INDEX_PREFIX
                 << EF->getName();
 
-  if (EF->hasIn())
+  if (Ins.size() == 1) {
     mOut << ", ain";
-  else
-    mOut << ", null";
+  } else if (Ins.size() > 1) {
+    mOut << ", new Allocation[]{ain_" << Ins[0]->getName().str();
+
+    for (size_t index = 1; index < Ins.size(); ++index) {
+      mOut << ", ain_" << Ins[index]->getName().str();
+    }
+
+    mOut << "}";
+
+  } else {
+    mOut << ", (Allocation) null";
+  }
 
   if (EF->hasOut() || EF->hasReturn())
     mOut << ", aout";
diff --git a/slang_rs_reflection.h b/slang_rs_reflection.h
index 4d3a576..0c2b773 100644
--- a/slang_rs_reflection.h
+++ b/slang_rs_reflection.h
@@ -233,6 +233,8 @@
   void genNewItemBufferIfNull(const char *Index);
   void genNewItemBufferPackerIfNull();
 
+  void genPairwiseDimCheck(std::string name0, std::string name1);
+
 public:
   RSReflectionJava(const RSContext *Context,
                    std::vector<std::string> *GeneratedFileNames,
diff --git a/slang_rs_reflection_cpp.cpp b/slang_rs_reflection_cpp.cpp
index a313193..e98901f 100644
--- a/slang_rs_reflection_cpp.cpp
+++ b/slang_rs_reflection_cpp.cpp
@@ -178,14 +178,19 @@
            E = mRSContext->export_foreach_end();
        I != E; I++) {
     const RSExportForEach *EF = *I;
-    const RSExportType *IET = EF->getInType();
     const RSExportType *OET = EF->getOutType();
-    if (IET) {
-      genTypeInstanceFromPointer(IET);
-    }
+
     if (OET) {
       genTypeInstanceFromPointer(OET);
     }
+
+    const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
+
+    for (RSExportForEach::InTypeIter BI = InTypes.begin(),
+         EI = InTypes.end(); BI != EI; BI++) {
+
+      genTypeInstanceFromPointer(*BI);
+    }
   }
 }
 
@@ -226,9 +231,12 @@
     mOut.indent() << FunctionStart;
 
     ArgumentList Arguments;
-    if (ForEach->hasIn()) {
+    const RSExportForEach::InVec &Ins = ForEach->getIns();
+    for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end();
+         BI != EI; BI++) {
+
       Arguments.push_back(std::make_pair(
-          "android::RSC::sp<const android::RSC::Allocation>", "ain"));
+        "android::RSC::sp<const android::RSC::Allocation>", (*BI)->getName()));
     }
 
     if (ForEach->hasOut() || ForEach->hasReturn()) {
@@ -348,7 +356,9 @@
         "void " + mClassName + "::forEach_" + ef->getName() + "(";
     mOut.indent() << FunctionStart;
 
-    if (ef->hasIn()) {
+    if (ef->hasIns()) {
+      // FIXME: Add support for kernels with multiple inputs.
+      assert(ef->getIns().size() == 1);
       Arguments.push_back(std::make_pair(
           "android::RSC::sp<const android::RSC::Allocation>", "ain"));
     }
@@ -372,10 +382,12 @@
     mOut << ")";
     mOut.startBlock();
 
-    const RSExportType *IET = ef->getInType();
     const RSExportType *OET = ef->getOutType();
-    if (IET) {
-      genTypeCheck(IET, "ain");
+    const RSExportForEach::InTypeVec &InTypes = ef->getInTypes();
+    if (ef->hasIns()) {
+      // FIXME: Add support for kernels with multiple inputs.
+      assert(ef->getIns().size() == 1);
+      genTypeCheck(InTypes[0], "ain");
     }
     if (OET) {
       genTypeCheck(OET, "aout");
@@ -392,7 +404,9 @@
     }
     mOut.indent() << "forEach(" << slot << ", ";
 
-    if (ef->hasIn()) {
+    if (ef->hasIns()) {
+      // FIXME: Add support for kernels with multiple inputs.
+      assert(ef->getIns().size() == 1);
       mOut << "ain, ";
     } else {
       mOut << "NULL, ";
diff --git a/slang_version.h b/slang_version.h
index aa236d5..b11d185 100644
--- a/slang_version.h
+++ b/slang_version.h
@@ -17,7 +17,9 @@
 #ifndef _FRAMEWORKS_COMPILE_SLANG_SLANG_VERSION_H_  // NOLINT
 #define _FRAMEWORKS_COMPILE_SLANG_SLANG_VERSION_H_
 
-#define RS_DEVELOPMENT_API -1
+#include <climits>
+
+#define RS_DEVELOPMENT_API UINT_MAX
 
 // API levels used by the standard Android SDK.
 // MR -> Maintenance Release
@@ -26,7 +28,6 @@
 // JB -> Jelly Bean
 // KK -> KitKat
 enum SlangTargetAPI {
-  SLANG_DEVELOPMENT_TARGET_API = RS_DEVELOPMENT_API,
   SLANG_MINIMUM_TARGET_API = 11,
   SLANG_HC_TARGET_API = 11,
   SLANG_HC_MR1_TARGET_API = 12,
@@ -37,7 +38,8 @@
   SLANG_JB_MR1_TARGET_API = 17,
   SLANG_JB_MR2_TARGET_API = 18,
   SLANG_KK_TARGET_API = 19,
-  SLANG_MAXIMUM_TARGET_API = RS_VERSION
+  SLANG_MAXIMUM_TARGET_API = RS_VERSION,
+  SLANG_DEVELOPMENT_TARGET_API = RS_DEVELOPMENT_API
 };
 // Note that RS_VERSION is defined at build time (see Android.mk for details).
 
diff --git a/tests/F_multi_in_target_version/multi_in_target_version.rs b/tests/F_multi_in_target_version/multi_in_target_version.rs
new file mode 100644
index 0000000..429bf5b
--- /dev/null
+++ b/tests/F_multi_in_target_version/multi_in_target_version.rs
@@ -0,0 +1,8 @@
+// -target-api 20
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL root(uint32_t in0, uint32_t in1, int x, int y) {
+  return 0;
+}
+
diff --git a/tests/F_multi_in_target_version/stderr.txt.expect b/tests/F_multi_in_target_version/stderr.txt.expect
new file mode 100644
index 0000000..1dc8a4f
--- /dev/null
+++ b/tests/F_multi_in_target_version/stderr.txt.expect
@@ -0,0 +1 @@
+multi_in_target_version.rs:5:43: error: Invalid parameter 'in1' for compute kernel root(). Kernels targeting SDK levels 11-20 may not use multiple input parameters.
diff --git a/tests/F_multi_in_target_version/stdout.txt.expect b/tests/F_multi_in_target_version/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_multi_in_target_version/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 7be0eb2..35dafc2 100644
--- a/tests/F_root_compute_really_bad/stderr.txt.expect
+++ b/tests/F_root_compute_really_bad/stderr.txt.expect
@@ -14,8 +14,8 @@
 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: Unrecognized parameter 'aout'. Compute kernel root_kernel() can only have one input parameter, 'x', and 'y'
+root_compute_really_bad.rs:15:31: error: Invalid parameter 'aout' for compute kernel root_kernel(). Kernels targeting SDK levels 11-20 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: Unrecognized parameter 'usrData'. Compute kernel root_kernel() can only have one input parameter, 'x', and 'y'
-root_compute_really_bad.rs:15:56: error: Unrecognized parameter 'x1'. Compute kernel root_kernel() can only have one input parameter, 'x', and 'y'
-root_compute_really_bad.rs:15:67: error: Unrecognized parameter 'y1'. Compute kernel root_kernel() can only have one input parameter, 'x', and 'y'
+root_compute_really_bad.rs:15:41: error: Invalid parameter 'usrData' for compute kernel root_kernel(). Kernels targeting SDK levels 11-20 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-20 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-20 may not use multiple input parameters.
diff --git a/tests/P_kernel_multi_in/kernel_multi_in.rs b/tests/P_kernel_multi_in/kernel_multi_in.rs
new file mode 100644
index 0000000..f38757b
--- /dev/null
+++ b/tests/P_kernel_multi_in/kernel_multi_in.rs
@@ -0,0 +1,7 @@
+// -target-api 0
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL multi_in(uint32_t in0, uint32_t in1) {
+  return 0;
+}
diff --git a/tests/P_kernel_multi_in/stderr.txt.expect b/tests/P_kernel_multi_in/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_kernel_multi_in/stderr.txt.expect
diff --git a/tests/P_kernel_multi_in/stdout.txt.expect b/tests/P_kernel_multi_in/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_kernel_multi_in/stdout.txt.expect
diff --git a/tests/P_multi_in_target_version/multi_in_target_version.rs b/tests/P_multi_in_target_version/multi_in_target_version.rs
new file mode 100644
index 0000000..2128778
--- /dev/null
+++ b/tests/P_multi_in_target_version/multi_in_target_version.rs
@@ -0,0 +1,8 @@
+// -target-api 0
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int RS_KERNEL root(uint32_t in0, uint32_t in1, int x, int y) {
+  return 0;
+}
+
diff --git a/tests/P_multi_in_target_version/stderr.txt.expect b/tests/P_multi_in_target_version/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_multi_in_target_version/stderr.txt.expect
diff --git a/tests/P_multi_in_target_version/stdout.txt.expect b/tests/P_multi_in_target_version/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_multi_in_target_version/stdout.txt.expect
diff --git a/tests/P_set_target_api_11/set_target_api_11.rs b/tests/P_set_target_api_11/set_target_api_11.rs
index d5708b0..412b21d 100644
--- a/tests/P_set_target_api_11/set_target_api_11.rs
+++ b/tests/P_set_target_api_11/set_target_api_11.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_12/set_target_api_12.rs b/tests/P_set_target_api_12/set_target_api_12.rs
index 87b1131..69e36a4 100644
--- a/tests/P_set_target_api_12/set_target_api_12.rs
+++ b/tests/P_set_target_api_12/set_target_api_12.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_13/set_target_api_13.rs b/tests/P_set_target_api_13/set_target_api_13.rs
index f0c3bf9..64c8cac 100644
--- a/tests/P_set_target_api_13/set_target_api_13.rs
+++ b/tests/P_set_target_api_13/set_target_api_13.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_14/set_target_api_14.rs b/tests/P_set_target_api_14/set_target_api_14.rs
index 1139b1a..b2be554 100644
--- a/tests/P_set_target_api_14/set_target_api_14.rs
+++ b/tests/P_set_target_api_14/set_target_api_14.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_15/set_target_api_15.rs b/tests/P_set_target_api_15/set_target_api_15.rs
index cdab0e1..f9d2b59 100644
--- a/tests/P_set_target_api_15/set_target_api_15.rs
+++ b/tests/P_set_target_api_15/set_target_api_15.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_16/set_target_api_16.rs b/tests/P_set_target_api_16/set_target_api_16.rs
index 9281b9f..a0f823f 100644
--- a/tests/P_set_target_api_16/set_target_api_16.rs
+++ b/tests/P_set_target_api_16/set_target_api_16.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_17/set_target_api_17.rs b/tests/P_set_target_api_17/set_target_api_17.rs
index cee7973..3361c48 100644
--- a/tests/P_set_target_api_17/set_target_api_17.rs
+++ b/tests/P_set_target_api_17/set_target_api_17.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_18/set_target_api_18.rs b/tests/P_set_target_api_18/set_target_api_18.rs
index 63ae635..a898735 100644
--- a/tests/P_set_target_api_18/set_target_api_18.rs
+++ b/tests/P_set_target_api_18/set_target_api_18.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_19/set_target_api_19.rs b/tests/P_set_target_api_19/set_target_api_19.rs
index f5811bd..6d290b9 100644
--- a/tests/P_set_target_api_19/set_target_api_19.rs
+++ b/tests/P_set_target_api_19/set_target_api_19.rs
@@ -9,7 +9,7 @@
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);
diff --git a/tests/P_set_target_api_development/set_target_api_development.rs b/tests/P_set_target_api_development/set_target_api_development.rs
index 223f0d4..0bcad66 100644
--- a/tests/P_set_target_api_development/set_target_api_development.rs
+++ b/tests/P_set_target_api_development/set_target_api_development.rs
@@ -1,11 +1,11 @@
-// -target-api -1
+// -target-api 0
 #pragma version(1)
 #pragma rs java_package_name(android.renderscript.cts)
 
 #define RS_MSG_TEST_PASSED 100
 #define RS_MSG_TEST_FAILED 101
 
-void check(int version) {
+void check(unsigned int version) {
     if (version != RS_VERSION) {
         rsDebug("version: ", version);
         rsDebug("RS_VERSION: ", RS_VERSION);