Merge "Test for improper kernel fusion." into klp-dev
diff --git a/tests/src/android/renderscript/cts/group1.rs b/tests/src/android/renderscript/cts/group1.rs
new file mode 100644
index 0000000..f1172dc
--- /dev/null
+++ b/tests/src/android/renderscript/cts/group1.rs
@@ -0,0 +1,13 @@
+#pragma version(1)
+#pragma rs java_package_name(android.renderscript.cts)
+
+#include "shared.rsh"
+
+rs_allocation aSharedInt;
+
+uint32_t  __attribute__((kernel)) setSharedInt(uint32_t x) {
+    if (x == 1) {
+        rsSetElementAt_int(aSharedInt, -5, 0);
+    }
+    return x;
+}
diff --git a/tests/src/android/renderscript/cts/group2.rs b/tests/src/android/renderscript/cts/group2.rs
new file mode 100644
index 0000000..f7b62dd
--- /dev/null
+++ b/tests/src/android/renderscript/cts/group2.rs
@@ -0,0 +1,32 @@
+#pragma version(1)
+#pragma rs java_package_name(android.renderscript.cts)
+
+#include "shared.rsh"
+
+rs_allocation aSharedInt;
+rs_allocation aFailed;
+
+static bool failed[2] = { false, false };
+
+void __attribute__((kernel)) getSharedInt(uint32_t in, uint32_t x) {
+    int v = rsGetElementAt_int(aSharedInt, 0);
+    if (in != x) {
+        rsDebug("Failed to read in on iteration: ", x);
+        rsDebug("Read: ", in);
+        failed[x] = true;
+    }
+    if (v != -5) {
+        rsDebug("Failed to read -5 on iteration: ", x);
+        rsDebug("Read: ", v);
+        failed[x] = true;
+    }
+}
+
+// Write out aFailed if either of our kernel instances read old data.
+void verify() {
+    for (int i = 0; i < 2; i++) {
+        if (failed[i]) {
+            rsSetElementAt_int(aFailed, 1, 0);
+        }
+    }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java
index 64496ef..c9a79c8 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java
@@ -202,13 +202,13 @@
         Type compareType = new Type.Builder(mRS, Element.I32(mRS)).create();
 
         ScriptC_scriptgroup node1, node2, node3, node4, node5, compare;
-        node1 = new ScriptC_scriptgroup(mRS, mRes, R.raw.scriptgroup);
-        node2 = new ScriptC_scriptgroup(mRS, mRes, R.raw.scriptgroup);
-        node3 = new ScriptC_scriptgroup(mRS, mRes, R.raw.scriptgroup);
-        node4 = new ScriptC_scriptgroup(mRS, mRes, R.raw.scriptgroup);
-        node5 = new ScriptC_scriptgroup(mRS, mRes, R.raw.scriptgroup);
+        node1 = new ScriptC_scriptgroup(mRS);
+        node2 = new ScriptC_scriptgroup(mRS);
+        node3 = new ScriptC_scriptgroup(mRS);
+        node4 = new ScriptC_scriptgroup(mRS);
+        node5 = new ScriptC_scriptgroup(mRS);
 
-        compare = new ScriptC_scriptgroup(mRS, mRes, R.raw.scriptgroup);
+        compare = new ScriptC_scriptgroup(mRS);
 
         Allocation in1, in2, out, resultAlloc;
         in1 = Allocation.createTyped(mRS, connect);
@@ -265,4 +265,50 @@
         assertTrue(result[0] == 2);
     }
 
+    /**
+     * Tests a case where a shared global variable is updated by the first kernel in a group,
+     * but then read by a subsequent kernel.
+     *
+     * The test ensures that we don't accidentally apply any fusion optimizations to the kernel
+     * pair, since there is a potential dependency that crosses the kernel cell boundary.
+     */
+    public void testScriptGroupSharedGlobal() {
+        Type i32 = new Type.Builder(mRS, Element.I32(mRS)).setX(1).create();
+        Type u32 = new Type.Builder(mRS, Element.U32(mRS)).setX(2).create();
+
+        Allocation aFailed = Allocation.createTyped(mRS, i32);
+        Allocation aSharedInt = Allocation.createTyped(mRS, i32);
+
+        ScriptC_group1 mG1 = new ScriptC_group1(mRS);
+        ScriptC_group2 mG2 = new ScriptC_group2(mRS);
+
+        mG1.set_aSharedInt(aSharedInt);
+        mG2.set_aSharedInt(aSharedInt);
+        mG2.set_aFailed(aFailed);
+
+        int [] Failed = new int [1];
+        Failed[0] = 0;
+        aFailed.copyFrom(Failed);
+
+        ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
+
+        // Writes to aSharedInt[x] in the kernel.
+        b.addKernel(mG1.getKernelID_setSharedInt());
+        // Reads aSharedInt[1] to verify it is -5.
+        b.addKernel(mG2.getKernelID_getSharedInt());
+        // If we fuse mG1/mG2, we won't see the update to the aSharedInt[1] during mG2 for x == 0.
+        // The update is only visible if we correctly identify the dependency and execute all of
+        // mG1 before starting on mG2.
+        b.addConnection(u32, mG1.getKernelID_setSharedInt(), mG2.getKernelID_getSharedInt());
+        ScriptGroup group = b.create();
+        group.execute();
+
+        mG2.invoke_verify();
+        aFailed.copyTo(Failed);
+        if (Failed[0] != 0) {
+            FoundError = true;
+        }
+
+        checkForErrors();
+    }
 }