IVGCVSW-7168 Add Conv2d and Constant support to TOSA Reference Backend

 * Added TOSA Conv2d and Constant mappings.
 * Added unique naming to mappings based on previous and following
   layers, so they are connected correctly.
 * Updated existing mappings with new naming convention.
 * Added all mappings to one main block in OptimizeSubgraphView.
 * Removed isMain from mapping functions.
 * Added Conv2d EndToEnd test.

Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: I27c3e238407c32379ce25a1f01dad11523ef5d2b
diff --git a/src/backends/tosaReference/TosaRefBackend.cpp b/src/backends/tosaReference/TosaRefBackend.cpp
index e3a516a..554bb10 100644
--- a/src/backends/tosaReference/TosaRefBackend.cpp
+++ b/src/backends/tosaReference/TosaRefBackend.cpp
@@ -83,16 +83,20 @@
                                                        const ModelOptions& modelOptions) const
 {
     OptimizationViews optimizationViews(modelOptions);
+
     auto handler = std::make_unique<TosaSerializationHandler>();
 
-    // A main block should only be added once.
-    bool isMain = true;
+    std::vector<std::string> graphInputs;
+    std::vector<std::string> graphOutputs;
+
+    std::vector<TosaSerializationOperator*> operators;
+    std::vector<TosaSerializationTensor*> tensors;
 
     auto it = subgraph.endIConnectable();
     while (it != subgraph.beginIConnectable())
     {
         --it;
-        Layer &base = *(PolymorphicDowncast<Layer*>(*it));
+        Layer& base = *(PolymorphicDowncast<Layer*>(*it));
 
         if(base.GetType() == armnn::LayerType::Input ||
            base.GetType() == armnn::LayerType::Output)
@@ -100,15 +104,44 @@
             continue;
         }
 
-        tosa::TosaSerializationBasicBlock* mappings = GetTosaMappingFromLayer(&base, isMain);
-        handler.get()->GetBlocks().push_back(mappings);
+        tosa::TosaSerializationBasicBlock* mappings = GetTosaMappingFromLayer(&base);
 
-        if(isMain)
+        // Loop through inputs to see if there are any graph inputs, if so save them.
+        // If it's an input to the graph "input" can be found in the string.
+        for (uint32_t i = 0; i < mappings->GetInputs().size(); i++)
         {
-            isMain = false;
+            std::basic_string<char> blockInputName = mappings->GetInputs()[i];
+
+            if (blockInputName.find("input") != std::string::npos)
+            {
+                graphInputs.push_back(blockInputName);
+            }
         }
+
+        // Loop through outputs to see if there are any graph outputs, if so save them.
+        // If it's an output to the graph "output" can be found in the string.
+        for (uint32_t i = 0; i < mappings->GetOutputs().size(); i++)
+        {
+            std::basic_string<char> blockOutputName = mappings->GetOutputs()[i];
+
+            if (blockOutputName.find("output") != std::string::npos)
+            {
+                graphOutputs.push_back(blockOutputName);
+            }
+        }
+
+        auto blockOperators = mappings->GetOperators();
+        operators.insert(operators.end(), blockOperators.begin(), blockOperators.end());
+
+        auto blockTensors = mappings->GetTensors();
+        tensors.insert(tensors.end(), blockTensors.begin(), blockTensors.end());
     }
 
+    // Add all mappings to main block, the TOSA Reference Model requires the full graph to be in one block called main.
+    auto* block = new TosaSerializationBasicBlock("main", operators, tensors, graphInputs, graphOutputs);
+
+    handler.get()->GetBlocks().push_back(block);
+
     auto compiledBlob =
             std::make_unique<PreCompiledObjectPtr>(handler.release(), DeleteAsType<TosaSerializationHandler>);
 
diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp
index ce4abbf..848b7ef 100644
--- a/src/backends/tosaReference/TosaRefLayerSupport.cpp
+++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp
@@ -102,7 +102,7 @@
         std::tuple<DType, DType> mappingType(input->GetDtype(), output->GetDtype());
 
         // Check Dtype from tensor (GetDtype)
-        supported &= CheckSupportRule(TosaContainerContains(mappingType, supportedMappingTypes),
+        supported &= CheckSupportRule(TosaContainerContainsTwoTypes(mappingType, supportedMappingTypes),
                                       reasonIfUnsupported,
                                       std::string("TOSA Reference Operator: " + opString + " for input: " +
                                           input->GetName() + " and output: " + output->GetName() +
@@ -125,6 +125,58 @@
     return supported;
 }
 
+static bool RunTosaLayerChecksInputWeightsOutputDataType(
+        TosaSerializationOperator* op,
+        const std::vector<TosaSerializationTensor*>& inputs,
+        const std::vector<TosaSerializationTensor*>& outputs,
+        const std::vector<Attribute>& supportedAttributes,
+        const std::vector<std::tuple<DType, DType, DType>>& supportedMappingTypes,
+        Optional<string&> reasonIfUnsupported)
+{
+    bool supported = true;
+
+    std::string opString = TosaOpToString(op->GetOp());
+
+    // Check Attribute from operator (GetAttribute)
+    supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported,
+                                  std::string("TOSA Reference Operator: " + opString +
+                                              " has an unsupported attribute.").c_str());
+
+    // Check combination of input, weights and output types.
+    // Bias is the same as output type, so it is covered.
+    std::tuple<DType, DType, DType> mappingTypes(inputs[0]->GetDtype(), inputs[1]->GetDtype(), outputs[0]->GetDtype());
+
+    // Check Dtype from tensor (GetDtype)
+    supported &= CheckSupportRule(TosaContainerContainsThreeTypes(mappingTypes, supportedMappingTypes),
+                                  reasonIfUnsupported,
+                                  std::string("TOSA Reference Operator: " + opString + " for input 0: " +
+                                              inputs[0]->GetName() + ", input 1: " + inputs[1]->GetName() +
+                                              " and output: " + outputs[0]->GetName() +
+                                              " has an unsupported input data type combination.").c_str());
+
+    for (auto input : inputs)
+    {
+        // Check Shape from tensor (GetShape)
+        supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input),
+                                      reasonIfUnsupported,
+                                      std::string("Tosa Reference Operator: " + opString + " for input: " +
+                                                  input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
+    }
+
+    for (auto output : outputs)
+    {
+        // Check Shape from tensor (GetShape)
+        supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output),
+                                      reasonIfUnsupported,
+                                      std::string("Tosa Reference Operator: " + opString + " for output: " +
+                                                  output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
+    }
+
+    return supported;
+}
+
+
+
 static bool IsTosaLayerSupported(TosaSerializationOperator* op,
                                  const std::vector<TosaSerializationTensor*>& inputs,
                                  const std::vector<TosaSerializationTensor*>& outputs,
@@ -134,10 +186,7 @@
     {
         case tosa::Op_ADD:
         {
-            std::vector<Attribute> supportedAttributes =
-            {
-                Attribute_NONE
-            };
+            std::vector<Attribute> supportedAttributes = { Attribute_NONE };
 
             // Only Int32, Fp32 and Fp16 are currently supported by the TOSA Reference Model.
             std::vector<DType> supportedTypes =
@@ -148,19 +197,46 @@
             };
 
             // Check the attribute, data types and bounds for inputs and outputs.
-            return RunTosaLayerChecksSingleDataType(op,
-                                                    inputs,
-                                                    outputs,
-                                                    supportedAttributes,
-                                                    supportedTypes,
-                                                    reasonIfUnsupported);
+            return RunTosaLayerChecksSingleDataType(
+                    op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
+        }
+        case tosa::Op_CONST:
+        {
+            std::vector<Attribute> supportedAttributes = { Attribute_NONE };
+
+            std::vector<DType> supportedTypes =
+            {
+                DType_FP16,
+                DType_FP32,
+                DType_UINT8,
+                DType_INT8,
+                DType_INT16,
+                DType_INT32,
+                DType_BOOL
+            };
+
+            // Check the attribute, data types and bounds for inputs and outputs.
+            return RunTosaLayerChecksSingleDataType(
+                    op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
+        }
+        case tosa::Op_CONV2D:
+        {
+            std::vector<Attribute> supportedAttributes = { Attribute_ConvAttribute };
+
+            std::vector<std::tuple<DType, DType, DType>> supportedTypesMapping =
+            {
+                std::tuple<DType, DType, DType>(DType_FP16, DType_FP16, DType_FP16),
+                std::tuple<DType, DType, DType>(DType_FP16, DType_FP16, DType_FP32),
+                std::tuple<DType, DType, DType>(DType_FP32, DType_FP32, DType_FP32),
+                std::tuple<DType, DType, DType>(DType_INT8, DType_INT8, DType_INT32)
+            };
+
+            return RunTosaLayerChecksInputWeightsOutputDataType(
+                    op, inputs, outputs, supportedAttributes, supportedTypesMapping, reasonIfUnsupported);
         }
         case tosa::Op_AVG_POOL2D:
         {
-            std::vector<Attribute> supportedAttributes =
-            {
-                Attribute_PoolAttribute
-            };
+            std::vector<Attribute> supportedAttributes = { Attribute_PoolAttribute };
 
             std::vector<std::tuple<DType, DType>> supportedTypesMapping =
             {
@@ -172,19 +248,12 @@
             };
 
             // Check the attribute, data types and bounds for inputs and outputs.
-            return RunTosaLayerChecksInputOutputDataType(op,
-                                                         inputs,
-                                                         outputs,
-                                                         supportedAttributes,
-                                                         supportedTypesMapping,
-                                                         reasonIfUnsupported);
+            return RunTosaLayerChecksInputOutputDataType(
+                    op, inputs, outputs, supportedAttributes, supportedTypesMapping, reasonIfUnsupported);
         }
         case tosa::Op_MAX_POOL2D:
         {
-            std::vector<Attribute> supportedAttributes =
-            {
-                Attribute_PoolAttribute
-            };
+            std::vector<Attribute> supportedAttributes = { Attribute_PoolAttribute };
 
             std::vector<DType> supportedTypes =
             {
@@ -195,19 +264,12 @@
             };
 
             // Check the attribute, data types and bounds for inputs and outputs.
-            return RunTosaLayerChecksSingleDataType(op,
-                                                    inputs,
-                                                    outputs,
-                                                    supportedAttributes,
-                                                    supportedTypes,
-                                                    reasonIfUnsupported);
+            return RunTosaLayerChecksSingleDataType(
+                    op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
         }
         case tosa::Op_PAD:
         {
-            std::vector<Attribute> supportedAttributes =
-            {
-                Attribute_PadAttribute
-            };
+            std::vector<Attribute> supportedAttributes = { Attribute_PadAttribute };
 
             std::vector<DType> supportedTypes =
             {
@@ -220,12 +282,8 @@
             };
 
             // Check the attribute, data types and bounds for inputs and outputs.
-            return RunTosaLayerChecksSingleDataType(op,
-                                                    inputs,
-                                                    outputs,
-                                                    supportedAttributes,
-                                                    supportedTypes,
-                                                    reasonIfUnsupported);
+            return RunTosaLayerChecksSingleDataType(
+                    op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
         }
         default:
             SetValueChecked(reasonIfUnsupported, "Operation is currently unsupported by the TOSA Reference Backend.");
@@ -248,15 +306,31 @@
 
     switch (type)
     {
+        case LayerType::Input:
+        case LayerType::Output:
+            return true;
         case LayerType::Addition:
             // Setup inputs and outputs
             inputInfos.push_back(&infos[0]);
             inputInfos.push_back(&infos[1]);
             outputInfos.push_back(&infos[2]);
             break;
-        case LayerType::Input:
-        case LayerType::Output:
-            return true;
+        case LayerType::Constant:
+            outputInfos.push_back(&infos[0]);
+            break;
+        case LayerType::Convolution2d:
+        {
+            inputInfos.push_back(&infos[0]); // input
+            outputInfos.push_back(&infos[1]); // output
+            inputInfos.push_back(&infos[2]); // weights
+
+            auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor);
+            if(conv2dDesc->m_BiasEnabled)
+            {
+                inputInfos.push_back(&infos[3]); // bias
+            }
+            break;
+        }
         case LayerType::Pooling2d:
             // Setup inputs and outputs
             inputInfos.push_back(&infos[0]);
@@ -266,7 +340,7 @@
             break;
     }
 
-    auto mappings = GetTosaMapping(type, inputInfos, outputInfos, descriptor, false);
+    auto mappings = GetTosaMapping(nullptr, type, inputInfos, outputInfos, descriptor);
     if (mappings->GetName() == "")
     {
         // There currently isn't a TOSA mapping for this layer, as the default was returned.
diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
index fbe1265..4245f0d 100644
--- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
@@ -6,6 +6,7 @@
 #include "backendsCommon/test/EndToEndTestImpl.hpp"
 
 #include "backendsCommon/test/AdditionEndToEndTestImpl.hpp"
+#include "backendsCommon/test/Convolution2dEndToEndTestImpl.hpp"
 #include "backendsCommon/test/Pooling2dEndToEndTestImpl.hpp"
 
 #include <doctest/doctest.h>
@@ -30,6 +31,17 @@
     AdditionEndToEndFloat16<DataType::Float16>(tosaDefaultBackends);
 }
 
+// Conv2d
+TEST_CASE("TosaRefConv2dEndtoEndTestFloat32")
+{
+    Convolution2dEndToEnd<armnn::DataType::Float32>(tosaDefaultBackends, armnn::DataLayout::NHWC);
+}
+
+TEST_CASE("TosaRefConv2dWithoutBiasEndtoEndTestFloat32")
+{
+    Convolution2dEndToEnd<armnn::DataType::Float32>(tosaDefaultBackends, armnn::DataLayout::NHWC, false);
+}
+
 // Max Pool 2D
 TEST_CASE("TosaRefMaxPool2DEndtoEndTestFloat32")
 {
diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
index 48eca34..e6fbbf9 100644
--- a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
@@ -58,11 +58,98 @@
 
     CHECK(!supported);
     REQUIRE(reasonIfNotSupported.find(
-        "TOSA Reference Operator: Op_ADD for input: Op_ADD_input0_") != std::string::npos);
+        "TOSA Reference Operator: Op_ADD for input: input0_") != std::string::npos);
     REQUIRE(reasonIfNotSupported.find(
-        "TOSA Reference Operator: Op_ADD for input: Op_ADD_input1_") != std::string::npos);
+        "TOSA Reference Operator: Op_ADD for input: input1_") != std::string::npos);
     REQUIRE(reasonIfNotSupported.find(
-        "TOSA Reference Operator: Op_ADD for output: Op_ADD_output0_") != std::string::npos);
+        "TOSA Reference Operator: Op_ADD for output: output0_") != std::string::npos);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceConstant")
+{
+    armnn::TensorInfo outputInfo({1,1,3,4}, armnn::DataType::Float32);
+
+    armnn::TosaRefLayerSupport supportChecker;
+    std::string reasonIfNotSupported;
+    auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Constant,
+                                                     {outputInfo},
+                                                     armnn::BaseDescriptor(),
+                                                     armnn::EmptyOptional(),
+                                                     armnn::EmptyOptional(),
+                                                     reasonIfNotSupported);
+
+    CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceConstantUnsupported")
+{
+    armnn::TensorInfo outputInfo({1,1,3,4}, armnn::DataType::Signed64);
+
+    armnn::TosaRefLayerSupport supportChecker;
+    std::string reasonIfNotSupported;
+    auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Constant,
+                                                     {outputInfo},
+                                                     armnn::BaseDescriptor(),
+                                                     armnn::EmptyOptional(),
+                                                     armnn::EmptyOptional(),
+                                                     reasonIfNotSupported);
+
+    CHECK(!supported);
+    REQUIRE(reasonIfNotSupported.find(
+            "TOSA Reference Operator: Op_CONST for output: constant_") != std::string::npos);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceConv2d")
+{
+    armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
+    armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
+    armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
+    armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
+
+    armnn::Convolution2dDescriptor desc;
+    desc.m_BiasEnabled = true;
+
+    armnn::TosaRefLayerSupport supportChecker;
+    std::string reasonIfNotSupported;
+    auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Convolution2d,
+                                                     {inputInfo, outputInfo, weightsInfo, biasesInfo},
+                                                     desc,
+                                                     armnn::EmptyOptional(),
+                                                     armnn::EmptyOptional(),
+                                                     reasonIfNotSupported);
+
+    CHECK(supported);
+}
+
+TEST_CASE("IsLayerSupportedTosaReferenceConv2dUnsupported")
+{
+    // If inputs and weights are Fp32, output must match.
+    armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
+    armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Signed64);
+    armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32, 0.0f, 0, true);
+    armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32, 0.0f, 0, true);
+
+    armnn::Convolution2dDescriptor desc;
+    desc.m_BiasEnabled = true;
+
+    armnn::TosaRefLayerSupport supportChecker;
+    std::string reasonIfNotSupported;
+    auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Convolution2d,
+                                                     {inputInfo, outputInfo, weightsInfo, biasesInfo},
+                                                     desc,
+                                                     armnn::EmptyOptional(),
+                                                     armnn::EmptyOptional(),
+                                                     reasonIfNotSupported);
+
+    CHECK(!supported);
+    REQUIRE(reasonIfNotSupported.find(
+            "TOSA Reference Operator: Op_CONV2D for input 0: input0_") != std::string::npos);
+    REQUIRE(reasonIfNotSupported.find(
+            "input 1: input1_") != std::string::npos);
+    REQUIRE(reasonIfNotSupported.find(
+            "and output: output0_") != std::string::npos);
+    REQUIRE(reasonIfNotSupported.find(
+            "has an unsupported input data type combination.") != std::string::npos);
 }
 
 TEST_CASE("IsLayerSupportedTosaReferenceMaxPooling2d")
@@ -150,9 +237,9 @@
 
     CHECK(!supported);
     REQUIRE(reasonIfNotSupported.find(
-        "TOSA Reference Operator: Op_MAX_POOL2D for input: Op_MAX_POOL2D_input0_") != std::string::npos);
+        "TOSA Reference Operator: Op_MAX_POOL2D for input: input0_") != std::string::npos);
     REQUIRE(reasonIfNotSupported.find(
-        "TOSA Reference Operator: Op_MAX_POOL2D for output: Op_MAX_POOL2D_output0_") != std::string::npos);
+        "TOSA Reference Operator: Op_MAX_POOL2D for output: output0_") != std::string::npos);
 }
 
 TEST_CASE("IsLayerSupportedTosaReferenceAvgPooling2dUnsupported_InputOutputDatatypeDifferent")
@@ -177,9 +264,9 @@
 
     CHECK(!supported);
     REQUIRE(reasonIfNotSupported.find(
-        "TOSA Reference Operator: Op_AVG_POOL2D for input: Op_PAD_intermediate0_") != std::string::npos);
+        "TOSA Reference Operator: Op_AVG_POOL2D for input: intermediate0_") != std::string::npos);
     REQUIRE(reasonIfNotSupported.find(
-        " and output: Op_AVG_POOL2D_output0_") != std::string::npos);
+        " and output: output0_") != std::string::npos);
     REQUIRE(reasonIfNotSupported.find(
         " has an unsupported input data type: 8 to output data type: 10") != std::string::npos);
 }
diff --git a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp
index ffdbf6f..ba353a3 100644
--- a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp
+++ b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp
@@ -23,13 +23,10 @@
 
 void TosaRefPreCompiledWorkload::Execute() const
 {
-    uint32_t numInputBuffers  = static_cast<uint32_t>(m_Data.m_Inputs.size());
-    uint32_t numOutputBuffers = static_cast<uint32_t>(m_Data.m_Outputs.size());
-
     tosa::TosaSerializationHandler* handler = static_cast<tosa::TosaSerializationHandler*>(m_Data.m_PreCompiledObject);
 
-    std::vector<std::string> input_names = handler->GetInputs();
-    std::vector<std::string> output_names = handler->GetOutputs();
+    std::vector<std::string> inputNames = handler->GetInputs();
+    std::vector<std::string> outputNames = handler->GetOutputs();
 
     TosaReference::IModelRunner runner;
     GraphStatus status;
@@ -42,29 +39,29 @@
     }
 
     // Set the inputs
-    for (uint32_t inputSlotIdx = 0; inputSlotIdx < numInputBuffers; ++inputSlotIdx)
+    for (uint32_t inputSlotIdx = 0; inputSlotIdx < inputNames.size(); ++inputSlotIdx)
     {
         DataType dataType = m_workloadInfo.m_InputTensorInfos[inputSlotIdx].GetDataType();
         switch (dataType)
         {
             case DataType::Float16:
-                SetInput<half_float::half>(runner, input_names[inputSlotIdx], inputSlotIdx);
+                SetInput<half_float::half>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
             case DataType::Float32:
-                SetInput<float>(runner, input_names[inputSlotIdx], inputSlotIdx);
+                SetInput<float>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
             case DataType::QAsymmU8:
             case DataType::QAsymmS8:
             case DataType::QSymmS8:
             case DataType::QSymmS16:
             case DataType::Signed32:
-                SetInput<int32_t>(runner, input_names[inputSlotIdx], inputSlotIdx);
+                SetInput<int32_t>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
             case DataType::Signed64:
-                SetInput<int64_t>(runner, input_names[inputSlotIdx], inputSlotIdx);
+                SetInput<int64_t>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
             case DataType::Boolean:
-                SetInput<unsigned char>(runner, input_names[inputSlotIdx], inputSlotIdx);
+                SetInput<unsigned char>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
             default:
                 throw armnn::Exception("Input data type is unsupported in TOSA Reference Backend.");
@@ -79,29 +76,29 @@
     }
 
     // Gets the outputs
-    for (uint32_t outputSlotIdx = 0; outputSlotIdx < numOutputBuffers; ++outputSlotIdx)
+    for (uint32_t outputSlotIdx = 0; outputSlotIdx < outputNames.size(); ++outputSlotIdx)
     {
         DataType dataType = m_workloadInfo.m_OutputTensorInfos[outputSlotIdx].GetDataType();
         switch (dataType)
         {
             case DataType::Float16:
-                GetOutput<half_float::half>(runner, output_names[outputSlotIdx], outputSlotIdx);
+                GetOutput<half_float::half>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
             case DataType::Float32:
-                GetOutput<float>(runner, output_names[outputSlotIdx], outputSlotIdx);
+                GetOutput<float>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
             case DataType::QAsymmU8:
             case DataType::QAsymmS8:
             case DataType::QSymmS8:
             case DataType::QSymmS16:
             case DataType::Signed32:
-                GetOutput<int32_t>(runner, output_names[outputSlotIdx], outputSlotIdx);
+                GetOutput<int32_t>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
             case DataType::Signed64:
-                GetOutput<int64_t>(runner, output_names[outputSlotIdx], outputSlotIdx);
+                GetOutput<int64_t>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
             case DataType::Boolean:
-                GetOutput<unsigned char>(runner, output_names[outputSlotIdx], outputSlotIdx);
+                GetOutput<unsigned char>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
             default:
                 throw armnn::Exception("Output data type is unsupported in TOSA Reference Backend.");