Support dummy root() and re-ordering in presence of non-root kernels.

BUG=6000538

Change-Id: Ib3ed249916d36acf68ab32e9216804ae1da5e991
diff --git a/slang_rs_context.cpp b/slang_rs_context.cpp
index 5d4f26d..242ecb1 100644
--- a/slang_rs_context.cpp
+++ b/slang_rs_context.cpp
@@ -183,6 +183,42 @@
   return (ET != NULL);
 }
 
+
+// Possibly re-order ForEach exports (maybe generating a dummy "root" function).
+// We require "root" to be listed as slot 0 of our exported compute kernels,
+// so this only needs to be created if we have other non-root kernels.
+void RSContext::cleanupForEach() {
+  bool foundNonRoot = false;
+  ExportForEachList::iterator begin = mExportForEach.begin();
+
+  for (ExportForEachList::iterator I = begin, E = mExportForEach.end();
+       I != E;
+       I++) {
+    RSExportForEach *EFE = *I;
+    if (!EFE->getName().compare("root")) {
+      if (I == begin) {
+        // Nothing to do, since it is the first function
+        return;
+      }
+
+      mExportForEach.erase(I);
+      mExportForEach.push_front(EFE);
+      return;
+    } else {
+      foundNonRoot = true;
+    }
+  }
+
+  // If we found a non-root kernel, but no root() function, we need to add a
+  // dummy version (so that script->script calls of rsForEach don't behave
+  // erratically).
+  if (foundNonRoot) {
+    RSExportForEach *DummyRoot = RSExportForEach::CreateDummyRoot(this);
+    mExportForEach.push_front(DummyRoot);
+  }
+}
+
+
 bool RSContext::processExport() {
   bool valid = true;
 
@@ -214,6 +250,10 @@
     }
   }
 
+  if (valid) {
+    cleanupForEach();
+  }
+
   // Finally, export type forcely set to be exported by user
   for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
            EE = mNeedExportTypes.end();
diff --git a/slang_rs_context.h b/slang_rs_context.h
index 030338b..4024300 100644
--- a/slang_rs_context.h
+++ b/slang_rs_context.h
@@ -89,6 +89,8 @@
   bool processExportFunc(const clang::FunctionDecl *FD);
   bool processExportType(const llvm::StringRef &Name);
 
+  void cleanupForEach();
+
   ExportVarList mExportVars;
   ExportFuncList mExportFuncs;
   ExportForEachList mExportForEach;
diff --git a/slang_rs_export_foreach.cpp b/slang_rs_export_foreach.cpp
index 7e3b5bb..3b759b4 100644
--- a/slang_rs_export_foreach.cpp
+++ b/slang_rs_export_foreach.cpp
@@ -224,7 +224,7 @@
 
   slangAssert(!Name.empty() && "Function must have a name");
 
-  FE = new RSExportForEach(Context, Name, FD);
+  FE = new RSExportForEach(Context, Name);
 
   if (!FE->validateAndConstructParams(Context, FD)) {
     return NULL;
@@ -303,6 +303,14 @@
   return FE;
 }
 
+RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
+  slangAssert(Context);
+  llvm::StringRef Name = "root";
+  RSExportForEach *FE = new RSExportForEach(Context, Name);
+  FE->mDummyRoot = true;
+  return FE;
+}
+
 bool RSExportForEach::isGraphicsRootRSFunc(int targetAPI,
                                            const clang::FunctionDecl *FD) {
   if (!isRootRSFunc(FD)) {
diff --git a/slang_rs_export_foreach.h b/slang_rs_export_foreach.h
index 0d6409c..c8b1dd0 100644
--- a/slang_rs_export_foreach.h
+++ b/slang_rs_export_foreach.h
@@ -53,14 +53,15 @@
   const clang::ParmVarDecl *mZ;
   const clang::ParmVarDecl *mAr;
 
+  bool mDummyRoot;
+
   // TODO(all): Add support for LOD/face when we have them
-  RSExportForEach(RSContext *Context, const llvm::StringRef &Name,
-         const clang::FunctionDecl *FD)
+  RSExportForEach(RSContext *Context, const llvm::StringRef &Name)
     : RSExportable(Context, RSExportable::EX_FOREACH),
       mName(Name.data(), Name.size()), mParamPacketType(NULL), mInType(NULL),
       mOutType(NULL), numParams(0), mSignatureMetadata(0),
       mIn(NULL), mOut(NULL), mUsrData(NULL),
-      mX(NULL), mY(NULL), mZ(NULL), mAr(NULL) {
+      mX(NULL), mY(NULL), mZ(NULL), mAr(NULL), mDummyRoot(false) {
     return;
   }
 
@@ -71,6 +72,8 @@
   static RSExportForEach *Create(RSContext *Context,
                                  const clang::FunctionDecl *FD);
 
+  static RSExportForEach *CreateDummyRoot(RSContext *Context);
+
   inline const std::string &getName() const {
     return mName;
   }
@@ -107,6 +110,10 @@
     return mSignatureMetadata;
   }
 
+  inline bool isDummyRoot() const {
+    return mDummyRoot;
+  }
+
   typedef RSExportRecordType::const_field_iterator const_param_iterator;
 
   inline const_param_iterator params_begin() const {
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index 4b2a04c..259931b 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -977,6 +977,15 @@
 }
 
 void RSReflection::genExportForEach(Context &C, const RSExportForEach *EF) {
+  if (EF->isDummyRoot()) {
+    // Skip reflection for dummy root() kernels. Note that we have to
+    // advance the next slot number for ForEach, however.
+    C.indent() << "//private final static int "RS_EXPORT_FOREACH_INDEX_PREFIX
+               << EF->getName() << " = " << C.getNextExportForEachSlot() << ";"
+               << std::endl;
+    return;
+  }
+
   C.indent() << "private final static int "RS_EXPORT_FOREACH_INDEX_PREFIX
              << EF->getName() << " = " << C.getNextExportForEachSlot() << ";"
              << std::endl;
diff --git a/tests/P_dummy_root/dummy_root.rs b/tests/P_dummy_root/dummy_root.rs
new file mode 100644
index 0000000..7731d94
--- /dev/null
+++ b/tests/P_dummy_root/dummy_root.rs
@@ -0,0 +1,5 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void foo (int *p) {
+}
diff --git a/tests/P_dummy_root/stderr.txt.expect b/tests/P_dummy_root/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_dummy_root/stderr.txt.expect
diff --git a/tests/P_dummy_root/stdout.txt.expect b/tests/P_dummy_root/stdout.txt.expect
new file mode 100644
index 0000000..cbcf1f9
--- /dev/null
+++ b/tests/P_dummy_root/stdout.txt.expect
@@ -0,0 +1 @@
+Generating ScriptC_dummy_root.java ...
diff --git a/tests/P_ooo_compute/ooo_compute.rs b/tests/P_ooo_compute/ooo_compute.rs
new file mode 100644
index 0000000..961bcd2
--- /dev/null
+++ b/tests/P_ooo_compute/ooo_compute.rs
@@ -0,0 +1,13 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void bar(int i, float f) {
+}
+
+void foo (int *p) {
+}
+
+void root(const int *ain, int *aout, const void *usrData,
+          uint32_t x, uint32_t y) {
+}
+
diff --git a/tests/P_ooo_compute/stderr.txt.expect b/tests/P_ooo_compute/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_ooo_compute/stderr.txt.expect
diff --git a/tests/P_ooo_compute/stdout.txt.expect b/tests/P_ooo_compute/stdout.txt.expect
new file mode 100644
index 0000000..48de3ac
--- /dev/null
+++ b/tests/P_ooo_compute/stdout.txt.expect
@@ -0,0 +1 @@
+Generating ScriptC_ooo_compute.java ...