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);