From 94b705249d2b4a3fc58cbd3b1b38580cc8dad636 Mon Sep 17 00:00:00 2001
From: CoreRasurae <luis.p.mendes@gmail.com>
Date: Fri, 24 Aug 2018 13:18:22 +0100
Subject: [PATCH] Fix: Fix arrays of AtomicInteger stored on local variables no
 longer fail with type cast exception - Partial fix for (refs #138) - support
 non-const indexed local variables

---
 .../aparapi/internal/writer/BlockWriter.java  | 19 +++---
 .../runtime/LocalAtomicVariableArrayTest.java | 68 ++++++++++++++++---
 2 files changed, 66 insertions(+), 21 deletions(-)

diff --git a/src/main/java/com/aparapi/internal/writer/BlockWriter.java b/src/main/java/com/aparapi/internal/writer/BlockWriter.java
index ba7aca90..013239d0 100644
--- a/src/main/java/com/aparapi/internal/writer/BlockWriter.java
+++ b/src/main/java/com/aparapi/internal/writer/BlockWriter.java
@@ -796,7 +796,7 @@ public abstract class BlockWriter{
        } else {
            //Arrays can be accessed through local variables instead of instance fields, thus, AccessField instruction
            //can be null.
-           LocalVariableConstIndexAccessor accessLocalVariable = getUltimateInstanceLocalVarAccess(arrayLoadInstruction);
+           AccessLocalVariable accessLocalVariable = getUltimateInstanceLocalVarAccess(arrayLoadInstruction);
            //Directly check for multi-dimensional array...
            return accessLocalVariable.getLocalVariableInfo().getVariableDescriptor().startsWith("[[");
        }      
@@ -813,27 +813,24 @@ public abstract class BlockWriter{
          load = load.getFirstChild();
       }
       
-      if (load instanceof I_ALOAD_0 || load instanceof I_ALOAD_1 || load instanceof I_ALOAD_2 || load instanceof I_ALOAD_3)  {
-          //It is not a Field Access
+      if (load instanceof I_ALOAD ||
+          load instanceof I_ALOAD_0 || load instanceof I_ALOAD_1 || load instanceof I_ALOAD_2 || load instanceof I_ALOAD_3)  {
+          //It is not a Field Access, it is either a constant index local variable (0..3), or is a variable indexed local variable (>3)
           return null;
       }
 
       return (AccessField) load;
    }
 
-   private LocalVariableConstIndexAccessor getUltimateInstanceLocalVarAccess(AccessArrayElement arrayLoadInstruction) {
+   private AccessLocalVariable getUltimateInstanceLocalVarAccess(AccessArrayElement arrayLoadInstruction) {
        Instruction load = arrayLoadInstruction.getArrayRef();
        while (load instanceof I_AALOAD) {
           load = load.getFirstChild();
        }
 
-       if (load instanceof I_ALOAD) {
-           return null;
-       }
-       
-       return (LocalVariableConstIndexAccessor)load;
-   }
-
+       return (AccessLocalVariable)load;
+   }   
+   
    public void writeMethod(MethodCall _methodCall, MethodEntry _methodEntry) throws CodeGenException {
       boolean noCL = _methodEntry.getOwnerClassModel().getNoCLMethods()
             .contains(_methodEntry.getNameAndTypeEntry().getNameUTF8Entry().getUTF8());
diff --git a/src/test/java/com/aparapi/runtime/LocalAtomicVariableArrayTest.java b/src/test/java/com/aparapi/runtime/LocalAtomicVariableArrayTest.java
index 26978d75..6f70f16c 100644
--- a/src/test/java/com/aparapi/runtime/LocalAtomicVariableArrayTest.java
+++ b/src/test/java/com/aparapi/runtime/LocalAtomicVariableArrayTest.java
@@ -72,32 +72,80 @@ public class LocalAtomicVariableArrayTest {
     }
 
     @Test
-    public void openCLTest() {
-        SimpleLocalVarKernel myKernel = new SimpleLocalVarKernel();
+    public void simpleConstIndexOpenCLTest() {
+        SimpleConstIndexLocalVarKernel myKernel = new SimpleConstIndexLocalVarKernel();
         Range range = openCLDevice.createRange(SIZE, SIZE);
         try {
             myKernel.execute(range);
-            assertEquals("Atomic increment doesn't match", SIZE, myKernel.atomics[1].get());
+            assertEquals("Atomic increment doesn't match, index 1", SIZE, myKernel.atomics[1].get());
+            assertEquals("Atomic increment doesn't match, index 2", SIZE, myKernel.atomics[2].get());
+            assertEquals("Atomic increment doesn't match, index 3", SIZE, myKernel.atomics[3].get());            
         } finally {
             myKernel.dispose();
         }
     }        
-    
-    public class SimpleLocalVarKernel extends Kernel {
+
+    @Test
+    public void simpleVarIndexOpenCLTest() {
+        SimpleVarIndexLocalVarKernel myKernel = new SimpleVarIndexLocalVarKernel();
+        Range range = openCLDevice.createRange(SIZE, SIZE);
+        try {
+            myKernel.execute(range);
+            assertEquals("Atomic increment doesn't match", SIZE, myKernel.atomics[4].get());
+        } finally {
+            myKernel.dispose();
+        }
+    }        
+
+    public class SimpleConstIndexLocalVarKernel extends Kernel {
         private AtomicInteger[] atomics = new AtomicInteger[SIZE];
 
-        public SimpleLocalVarKernel() {
+        public SimpleConstIndexLocalVarKernel() {
             for (int i = 0; i < atomics.length; i++) {
                 atomics[i] = new AtomicInteger(0);
             }
         }
 
-        @Override public void run() {
-            atomicUpdate(atomics, 1);
+        @Override 
+        public void run() {
+            atomicUpdate1(atomics, 1);
+            atomicUpdate2(2, atomics);
+            atomicUpdate3(3, 0, atomics);
+        }
+
+        public int atomicUpdate1(AtomicInteger[] arr, int index) {
+            //Exercises I_ALOAD_1
+            return atomicInc(arr[index]);    
         }
 
-        public int atomicUpdate(AtomicInteger[] arr, int index) {
+        public int atomicUpdate2(int index, AtomicInteger[] arr) {
+            //Exercises I_ALOAD_2
             return atomicInc(arr[index]);    
-        }               
+        }
+        
+        public int atomicUpdate3(int index, int indexB, AtomicInteger[] arr) {
+            //Exercises I_ALOAD_3
+            return atomicInc(arr[index+indexB]);    
+        }     
+    }
+    
+    public class SimpleVarIndexLocalVarKernel extends Kernel {
+        private AtomicInteger[] atomics = new AtomicInteger[SIZE];
+
+        public SimpleVarIndexLocalVarKernel() {
+            for (int i = 0; i < atomics.length; i++) {
+                atomics[i] = new AtomicInteger(0);
+            }
+        }
+
+        @Override 
+        public void run() {
+            atomicUpdate4(4, 0, 0, atomics);
+        }
+
+        public int atomicUpdate4(int index, int indexB, int indexC, AtomicInteger[] arr) {
+            //Exercises I_ALOAD - when index is greater than 3
+            return atomicInc(arr[index+indexB+indexC]);
+        }   
     }
 }
-- 
GitLab