IVGCVSW-3159 Support QSymm16 for Splitter workloads

Change-Id: I9af5d2d8ade97b9ecd2e6fbf13db9fa3bb622ed8
Signed-off-by: Ruomei Yan <ruomei.yan@arm.com>
diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt
index e2f93d7..e57a40a 100644
--- a/src/backends/reference/workloads/CMakeLists.txt
+++ b/src/backends/reference/workloads/CMakeLists.txt
@@ -103,10 +103,8 @@
     RefSoftmaxWorkload.hpp
     RefSpaceToBatchNdWorkload.cpp
     RefSpaceToBatchNdWorkload.hpp
-    RefSplitterFloat32Workload.cpp
-    RefSplitterFloat32Workload.hpp
-    RefSplitterUint8Workload.cpp
-    RefSplitterUint8Workload.hpp
+    RefSplitterWorkload.cpp
+    RefSplitterWorkload.hpp
     RefStridedSliceWorkload.cpp
     RefStridedSliceWorkload.hpp
     RefWorkloads.hpp
@@ -120,6 +118,7 @@
     SpaceToBatchNd.hpp
     SpaceToBatchNd.cpp
     Splitter.hpp
+    Splitter.cpp
     StridedSlice.hpp
     StridedSlice.cpp
     StringMapping.cpp
diff --git a/src/backends/reference/workloads/RefSplitterFloat32Workload.cpp b/src/backends/reference/workloads/RefSplitterFloat32Workload.cpp
deleted file mode 100644
index 75611da..0000000
--- a/src/backends/reference/workloads/RefSplitterFloat32Workload.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright © 2017 Arm Ltd. All rights reserved.
-// SPDX-License-Identifier: MIT
-//
-
-#include "RefSplitterFloat32Workload.hpp"
-
-#include "Splitter.hpp"
-
-#include "Profiling.hpp"
-
-namespace armnn
-{
-
-void RefSplitterFloat32Workload::Execute() const
-{
-    ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefSplitterFloat32Workload_Execute");
-    Splitter<float>(m_Data);
-}
-
-} //namespace armnn
diff --git a/src/backends/reference/workloads/RefSplitterFloat32Workload.hpp b/src/backends/reference/workloads/RefSplitterFloat32Workload.hpp
deleted file mode 100644
index 502eb35..0000000
--- a/src/backends/reference/workloads/RefSplitterFloat32Workload.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright © 2017 Arm Ltd. All rights reserved.
-// SPDX-License-Identifier: MIT
-//
-
-#pragma once
-
-#include <backendsCommon/Workload.hpp>
-#include <backendsCommon/WorkloadData.hpp>
-
-namespace armnn
-{
-
-class RefSplitterFloat32Workload : public Float32Workload<SplitterQueueDescriptor>
-{
-public:
-    using Float32Workload<SplitterQueueDescriptor>::Float32Workload;
-    virtual void Execute() const override;
-};
-
-} //namespace armnn
diff --git a/src/backends/reference/workloads/RefSplitterUint8Workload.cpp b/src/backends/reference/workloads/RefSplitterUint8Workload.cpp
deleted file mode 100644
index ca9f5db..0000000
--- a/src/backends/reference/workloads/RefSplitterUint8Workload.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright © 2017 Arm Ltd. All rights reserved.
-// SPDX-License-Identifier: MIT
-//
-
-#include "RefSplitterUint8Workload.hpp"
-
-#include "Splitter.hpp"
-
-#include "Profiling.hpp"
-
-namespace armnn
-{
-
-void RefSplitterUint8Workload::Execute() const
-{
-    ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefSplitterUint8Workload_Execute");
-    Splitter<uint8_t>(m_Data);
-}
-
-} //namespace armnn
diff --git a/src/backends/reference/workloads/RefSplitterWorkload.cpp b/src/backends/reference/workloads/RefSplitterWorkload.cpp
new file mode 100644
index 0000000..ffe4eb8
--- /dev/null
+++ b/src/backends/reference/workloads/RefSplitterWorkload.cpp
@@ -0,0 +1,20 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "RefSplitterWorkload.hpp"
+#include "Splitter.hpp"
+#include "RefWorkloadUtils.hpp"
+#include "Profiling.hpp"
+
+namespace armnn
+{
+
+void RefSplitterWorkload::Execute() const
+{
+    ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefSplitterWorkload_Execute");
+    Split(m_Data);
+}
+
+} //namespace armnn
diff --git a/src/backends/reference/workloads/RefSplitterUint8Workload.hpp b/src/backends/reference/workloads/RefSplitterWorkload.hpp
similarity index 60%
rename from src/backends/reference/workloads/RefSplitterUint8Workload.hpp
rename to src/backends/reference/workloads/RefSplitterWorkload.hpp
index d9b6aaf..95cc4a5 100644
--- a/src/backends/reference/workloads/RefSplitterUint8Workload.hpp
+++ b/src/backends/reference/workloads/RefSplitterWorkload.hpp
@@ -7,14 +7,16 @@
 
 #include <backendsCommon/Workload.hpp>
 #include <backendsCommon/WorkloadData.hpp>
+#include "Decoders.hpp"
+#include "Encoders.hpp"
 
 namespace armnn
 {
 
-class RefSplitterUint8Workload : public Uint8Workload<SplitterQueueDescriptor>
+class RefSplitterWorkload : public BaseWorkload<SplitterQueueDescriptor>
 {
 public:
-    using Uint8Workload<SplitterQueueDescriptor>::Uint8Workload;
+    using BaseWorkload<SplitterQueueDescriptor>::BaseWorkload;
     virtual void Execute() const override;
 };
 
diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp
index ab3da88..c20e2f6 100644
--- a/src/backends/reference/workloads/RefWorkloads.hpp
+++ b/src/backends/reference/workloads/RefWorkloads.hpp
@@ -10,7 +10,7 @@
 #include "ConvImpl.hpp"
 #include "RefConstantWorkload.hpp"
 #include "RefConvolution2dWorkload.hpp"
-#include "RefSplitterUint8Workload.hpp"
+#include "RefSplitterWorkload.hpp"
 #include "RefResizeBilinearUint8Workload.hpp"
 #include "RefL2NormalizationFloat32Workload.hpp"
 #include "RefActivationWorkload.hpp"
@@ -39,7 +39,6 @@
 #include "Activation.hpp"
 #include "Concatenate.hpp"
 #include "RefSpaceToBatchNdWorkload.hpp"
-#include "RefSplitterFloat32Workload.hpp"
 #include "RefStridedSliceWorkload.hpp"
 #include "Pooling2d.hpp"
 #include "RefFakeQuantizationFloat32Workload.hpp"
diff --git a/src/backends/reference/workloads/Splitter.cpp b/src/backends/reference/workloads/Splitter.cpp
new file mode 100644
index 0000000..3bddfb0
--- /dev/null
+++ b/src/backends/reference/workloads/Splitter.cpp
@@ -0,0 +1,94 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "RefWorkloadUtils.hpp"
+#include <backendsCommon/WorkloadData.hpp>
+#include <armnn/Tensor.hpp>
+
+#include <boost/assert.hpp>
+#include "Splitter.hpp"
+
+#include <cmath>
+#include <limits>
+
+#include "Decoders.hpp"
+#include "Encoders.hpp"
+
+namespace armnn
+{
+
+void Split(const SplitterQueueDescriptor& data)
+{
+    const TensorInfo& inputInfo = GetTensorInfo(data.m_Inputs[0]);
+
+    std::unique_ptr<Decoder<float>> decoderPtr =
+        MakeDecoder<float>(inputInfo, data.m_Inputs[0]->Map());
+    Decoder<float>& decoder = *decoderPtr;
+
+    for (unsigned int index = 0; index < inputInfo.GetNumElements(); ++index)
+    {
+        unsigned int indices[MaxNumOfTensorDimensions] = { 0 };
+
+        unsigned int indexRemainder = index;
+        unsigned int dimensionStride = inputInfo.GetNumElements();
+
+        for (unsigned int i = 0; i<inputInfo.GetNumDimensions(); i++)
+        {
+            dimensionStride /= inputInfo.GetShape()[i];
+            indices[i] = indexRemainder / dimensionStride; // Use integer division to round down.
+            indexRemainder -= indices[i] * dimensionStride;
+        }
+
+        for (unsigned int viewIdx = 0; viewIdx < data.m_ViewOrigins.size(); ++viewIdx)
+        {
+            SplitterQueueDescriptor::ViewOrigin const& view = data.m_ViewOrigins[viewIdx];
+
+            //Split view extents are defined by the size of (the corresponding) input tensor.
+            const TensorInfo& outputInfo = GetTensorInfo(data.m_Outputs[viewIdx]);
+            BOOST_ASSERT(outputInfo.GetNumDimensions() == inputInfo.GetNumDimensions());
+
+            // Check all dimensions to see if this element is inside the given input view.
+            bool insideView = true;
+            for (unsigned int i = 0; i<outputInfo.GetNumDimensions(); i++)
+            {
+                if (indices[i] < view.m_Origin[i])
+                {
+                    insideView = false;
+                }
+                if (indices[i] >= view.m_Origin[i] + outputInfo.GetShape()[i])
+                {
+                    insideView = false;
+                }
+            }
+
+            if (insideView)
+            {
+                std::unique_ptr<Encoder<float>> encoderPtr =
+                    MakeEncoder<float>(outputInfo, data.m_Outputs[viewIdx]->Map());
+                Encoder<float>& encoder = *encoderPtr;
+
+                unsigned int outIndex = 0;
+                unsigned int dimensionStride = 1;
+                float inputValue = 0.f;
+
+                for (unsigned int i = outputInfo.GetNumDimensions(); i-- > 0;)
+                {
+                    outIndex += dimensionStride * (indices[i] - view.m_Origin[i]);
+                    dimensionStride *= outputInfo.GetShape()[i];
+                }
+
+                decoder += index;
+                inputValue = decoder.Get();
+                decoder -= index;
+
+                encoder += outIndex;
+                encoder.Set(inputValue);
+                break;
+            }
+        }
+    }
+}
+
+}
\ No newline at end of file
diff --git a/src/backends/reference/workloads/Splitter.hpp b/src/backends/reference/workloads/Splitter.hpp
index 0e522d5..271c6fd 100644
--- a/src/backends/reference/workloads/Splitter.hpp
+++ b/src/backends/reference/workloads/Splitter.hpp
@@ -6,10 +6,8 @@
 #pragma once
 
 #include "RefWorkloadUtils.hpp"
-
 #include <backendsCommon/WorkloadData.hpp>
 #include <armnn/Tensor.hpp>
-
 #include <boost/assert.hpp>
 
 namespace armnn
@@ -80,4 +78,5 @@
     }
 }
 
+void Split(const SplitterQueueDescriptor& data);
 } //namespace armnn