IVGCVSW-2503 Refactor RefElementwiseWorkload around Equal and Greater

	* Remove Equal and Greater from RefElementwiseWorkload
	* Create RefComparisonWorkload and add Equal and Greater
	* Update ElementwiseFunction for different input/output types
	* Update TfParser to create Equal/Greater with Boolean output
	* Update relevant tests to check for Boolean comparison

Change-Id: I299b7f2121769c960ac0c6139764a5f3c89c9c32
diff --git a/src/armnn/LayerSupportCommon.hpp b/src/armnn/LayerSupportCommon.hpp
index 109728c..70b5f18 100644
--- a/src/armnn/LayerSupportCommon.hpp
+++ b/src/armnn/LayerSupportCommon.hpp
@@ -12,13 +12,15 @@
 namespace armnn
 {
 
-template<typename Float16Func, typename Float32Func, typename Uint8Func, typename Int32Func, typename ... Params>
+template<typename Float16Func, typename Float32Func, typename Uint8Func, typename Int32Func, typename BooleanFunc,
+         typename ... Params>
 bool IsSupportedForDataTypeGeneric(Optional<std::string&> reasonIfUnsupported,
                                    DataType dataType,
                                    Float16Func float16FuncPtr,
                                    Float32Func float32FuncPtr,
                                    Uint8Func uint8FuncPtr,
                                    Int32Func int32FuncPtr,
+                                   BooleanFunc booleanFuncPtr,
                                    Params&&... params)
 {
     switch(dataType)
@@ -31,6 +33,8 @@
             return uint8FuncPtr(reasonIfUnsupported, std::forward<Params>(params)...);
         case DataType::Signed32:
             return int32FuncPtr(reasonIfUnsupported, std::forward<Params>(params)...);
+        case DataType::Boolean:
+            return booleanFuncPtr(reasonIfUnsupported, std::forward<Params>(params)...);
         default:
             return false;
     }
diff --git a/src/armnn/test/TensorHelpers.hpp b/src/armnn/test/TensorHelpers.hpp
index 06818d3..fcaa077 100644
--- a/src/armnn/test/TensorHelpers.hpp
+++ b/src/armnn/test/TensorHelpers.hpp
@@ -67,11 +67,16 @@
     return SelectiveComparer<T, armnn::IsQuantizedType<T>()>::Compare(a, b);
 };
 
-
+template<typename T>
+bool SelectiveCompareBoolean(T a, T b)
+{
+    return (((a == 0) && (b == 0)) || ((a != 0) && (b != 0)));
+};
 
 template <typename T, std::size_t n>
 boost::test_tools::predicate_result CompareTensors(const boost::multi_array<T, n>& a,
-                                                   const boost::multi_array<T, n>& b)
+                                                   const boost::multi_array<T, n>& b,
+                                                   bool compareBoolean = false)
 {
     // Checks they are same shape.
     for (unsigned int i=0; i<n; i++)
@@ -103,7 +108,17 @@
 
     while (true)
     {
-        bool comparison = SelectiveCompare(a(indices), b(indices));
+        bool comparison;
+        // As true for uint8_t is non-zero (1-255) we must have a dedicated compare for Booleans.
+        if(compareBoolean)
+        {
+            comparison = SelectiveCompareBoolean(a(indices), b(indices));
+        }
+        else
+        {
+            comparison = SelectiveCompare(a(indices), b(indices));
+        }
+
         if (!comparison)
         {
             ++numFailedElements;
diff --git a/src/armnn/test/UnitTests.hpp b/src/armnn/test/UnitTests.hpp
index f489ca0..04e91ad 100644
--- a/src/armnn/test/UnitTests.hpp
+++ b/src/armnn/test/UnitTests.hpp
@@ -41,7 +41,7 @@
         "The test name does not match the supportedness it is reporting");
     if (testResult.supported)
     {
-        BOOST_TEST(CompareTensors(testResult.output, testResult.outputExpected));
+        BOOST_TEST(CompareTensors(testResult.output, testResult.outputExpected, testResult.compareBoolean));
     }
 }
 
diff --git a/src/armnnTfParser/TfParser.cpp b/src/armnnTfParser/TfParser.cpp
index 43b0d86..8096274 100755
--- a/src/armnnTfParser/TfParser.cpp
+++ b/src/armnnTfParser/TfParser.cpp
@@ -1741,6 +1741,33 @@
     return {input0Slot, input1Slot};
 }
 
+ParsedTfOperationPtr TfParser::ProcessComparisonLayer(
+    IOutputSlot* input0Slot,
+    IOutputSlot* input1Slot,
+    IConnectableLayer* const layer,
+    const tensorflow::NodeDef& nodeDef)
+{
+    input0Slot->Connect(layer->GetInputSlot(0));
+    input1Slot->Connect(layer->GetInputSlot(1));
+
+    TensorInfo outputInfo = input0Slot->GetTensorInfo();
+    outputInfo.SetDataType(DataType::Boolean);
+    std::vector<unsigned int> outputShape;
+
+    const TensorShape& input0Shape = input0Slot->GetTensorInfo().GetShape();
+    const TensorShape& input1Shape = input1Slot->GetTensorInfo().GetShape();
+
+    for (unsigned int i = 0; i < input0Shape.GetNumDimensions(); i++)
+    {
+        outputShape.push_back(std::max(input0Shape[i], input1Shape[i]));
+    }
+
+    outputInfo.SetShape(TensorShape(input0Shape.GetNumDimensions(), outputShape.data()));
+    layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+    return std::make_unique<SingleLayerParsedTfOperation>(this, nodeDef, layer);
+}
+
 ParsedTfOperationPtr TfParser::ProcessElementwiseLayer(
         IOutputSlot* input0Slot,
         IOutputSlot* input1Slot,
@@ -1812,7 +1839,7 @@
 
     IConnectableLayer* const layer = m_Network->AddGreaterLayer(nodeDef.name().c_str());
 
-    return ProcessElementwiseLayer(input0Slot, input1Slot, layer, nodeDef);
+    return ProcessComparisonLayer(input0Slot, input1Slot, layer, nodeDef);
 }
 
 ParsedTfOperationPtr TfParser::ParseEqual(const tensorflow::NodeDef& nodeDef,
@@ -1824,7 +1851,7 @@
 
     IConnectableLayer* const layer = m_Network->AddEqualLayer(nodeDef.name().c_str());
 
-    return ProcessElementwiseLayer(input0Slot, input1Slot, layer, nodeDef);
+    return ProcessComparisonLayer(input0Slot, input1Slot, layer, nodeDef);
 }
 
 ParsedTfOperationPtr TfParser::ParseMinimum(const tensorflow::NodeDef& nodeDef,
diff --git a/src/armnnTfParser/TfParser.hpp b/src/armnnTfParser/TfParser.hpp
index 9a7d782..2b80941 100644
--- a/src/armnnTfParser/TfParser.hpp
+++ b/src/armnnTfParser/TfParser.hpp
@@ -187,6 +187,12 @@
     std::pair<armnn::IOutputSlot*, armnn::IOutputSlot*> ProcessElementwiseInputSlots(
             const tensorflow::NodeDef& nodeDef, const std::string& layerName);
 
+    ParsedTfOperationPtr ProcessComparisonLayer(
+        armnn::IOutputSlot* input0Slot,
+        armnn::IOutputSlot* input1Slot,
+        armnn::IConnectableLayer* const layer,
+        const tensorflow::NodeDef& nodeDef);
+
     ParsedTfOperationPtr ProcessElementwiseLayer(
             armnn::IOutputSlot* input0Slot,
             armnn::IOutputSlot* input1Slot,
diff --git a/src/armnnTfParser/test/Equal.cpp b/src/armnnTfParser/test/Equal.cpp
index 43a1c6a..2dce822 100644
--- a/src/armnnTfParser/test/Equal.cpp
+++ b/src/armnnTfParser/test/Equal.cpp
@@ -91,9 +91,9 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseEqualTwoByTwo, EqualTwoByTwo)
 {
-    RunTest<2>({ { "input0", { 1.0f, 2.0f, 3.0f, 2.0f } },
-                 { "input1", { 1.0f, 5.0f, 2.0f, 2.0f } } },
-               { { "output", { 1.0f, 0.0f, 0.0f, 1.0f } } });
+    RunComparisonTest<2>({ { "input0", { 1.0f, 2.0f, 3.0f, 2.0f } },
+                           { "input1", { 1.0f, 5.0f, 2.0f, 2.0f } } },
+                         { { "output", { 1, 0, 0, 1 } } });
 }
 
 struct EqualBroadcast1DAnd4D : public EqualFixtureAutoSetup
@@ -103,9 +103,9 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseEqualBroadcast1DToTwoByTwo, EqualBroadcast1DAnd4D)
 {
-    RunTest<4>({ { "input0", { 2.0f } },
-                 { "input1", { 1.0f, 2.0f, 3.0f, 2.0f } } },
-               { { "output", { 0.0f, 1.0f, 0.0f, 1.0f } } });
+    RunComparisonTest<4>({ { "input0", { 2.0f } },
+                           { "input1", { 1.0f, 2.0f, 3.0f, 2.0f } } },
+                         { { "output", { 0, 1, 0, 1 } } });
 }
 
 struct EqualBroadcast4DAnd1D : public EqualFixtureAutoSetup
@@ -115,9 +115,9 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseEqualBroadcast4DAnd1D, EqualBroadcast4DAnd1D)
 {
-    RunTest<4>({ { "input0", { 1.0f, 2.0f, 3.0f, 2.0f } },
-                 { "input1", { 3.0f } } },
-               { { "output", { 0.0f, 0.0f, 1.0f, 0.0f } } });
+    RunComparisonTest<4>({ { "input0", { 1.0f, 2.0f, 3.0f, 2.0f } },
+                           { "input1", { 3.0f } } },
+                         { { "output", { 0, 0, 1, 0 } } });
 }
 
 struct EqualMultiDimBroadcast : public EqualFixtureAutoSetup
@@ -127,13 +127,13 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseEqualMultiDimBroadcast, EqualMultiDimBroadcast)
 {
-    RunTest<4>({ { "input0", { 1.0f, 2.0f } },
-                 { "input1", { 1.0f, 2.0f, 3.0f,
-                               3.0f, 2.0f, 2.0f } } },
-               { { "output", { 1.0f, 0.0f, 0.0f,
-                               0.0f, 1.0f, 0.0f,
-                               0.0f, 0.0f, 0.0f,
-                               0.0f, 1.0f, 1.0f } } });
+    RunComparisonTest<4>({ { "input0", { 1.0f, 2.0f } },
+                           { "input1", { 1.0f, 2.0f, 3.0f,
+                                         3.0f, 2.0f, 2.0f } } },
+                         { { "output", { 1, 0, 0,
+                                         0, 1, 0,
+                                         0, 0, 0,
+                                         0, 1, 1 } } });
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/armnnTfParser/test/Greater.cpp b/src/armnnTfParser/test/Greater.cpp
index f11c199..d1e7939 100644
--- a/src/armnnTfParser/test/Greater.cpp
+++ b/src/armnnTfParser/test/Greater.cpp
@@ -91,9 +91,9 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseGreaterTwoByTwo, GreaterFixtureTwoByTwo)
 {
-    RunTest<2>({ { "input0", { 1.0f, 2.0f, 3.0f, 4.0f} },
-                 { "input1", { 1.0f, 5.0f, 2.0f, 2.0f} } },
-               { { "output", { 0.0f, 0.0f, 1.0f, 1.0f} } });
+    RunComparisonTest<2>({ { "input0", { 1.0f, 2.0f, 3.0f, 4.0f} },
+                           { "input1", { 1.0f, 5.0f, 2.0f, 2.0f} } },
+                         { { "output", { 0, 0, 1, 1} } });
 }
 
 struct GreaterBroadcast1DAnd4D : public GreaterFixtureAutoSetup
@@ -103,9 +103,9 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseGreaterBroadcast1DToTwoByTwo, GreaterBroadcast1DAnd4D)
 {
-    RunTest<4>({ { "input0", { 2.0f } },
-                 { "input1", { 1.0f, 2.0f, 3.0f, 2.0f } } },
-               { { "output", { 1.0f, 0.0f, 0.0f, 0.0f } } });
+    RunComparisonTest<4>({ { "input0", { 2.0f } },
+                           { "input1", { 1.0f, 2.0f, 3.0f, 2.0f } } },
+                         { { "output", { 1, 0, 0, 0 } } });
 }
 
 struct GreaterBroadcast4DAnd1D : public GreaterFixtureAutoSetup
@@ -115,9 +115,9 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseGreaterBroadcast4DAnd1D, GreaterBroadcast4DAnd1D)
 {
-    RunTest<4>({ { "input0", { 1.0f, 2.0f, 3.0f, 2.0f } },
-                 { "input1", { 3.0f } } },
-               { { "output", { 0.0f, 0.0f, 0.0f, 0.0f } } });
+    RunComparisonTest<4>({ { "input0", { 1.0f, 2.0f, 3.0f, 2.0f } },
+                           { "input1", { 3.0f } } },
+                         { { "output", { 0, 0, 0, 0 } } });
 }
 
 struct GreaterMultiDimBroadcast : public GreaterFixtureAutoSetup
@@ -127,13 +127,13 @@
 
 BOOST_FIXTURE_TEST_CASE(ParseGreaterMultiDimBroadcast, GreaterMultiDimBroadcast)
 {
-    RunTest<4>({ { "input0", { 1.0f, 2.0f } },
-                 { "input1", { 1.0f, 2.0f, 3.0f,
-                               3.0f, 2.0f, 2.0f } } },
-               { { "output", { 0.0f, 0.0f, 0.0f,
-                               1.0f, 0.0f, 0.0f,
-                               0.0f, 0.0f, 0.0f,
-                               0.0f, 0.0f, 0.0f } } });
+    RunComparisonTest<4>({ { "input0", { 1.0f, 2.0f } },
+                           { "input1", { 1.0f, 2.0f, 3.0f,
+                                         3.0f, 2.0f, 2.0f } } },
+                         { { "output", { 0, 0, 0,
+                                         1, 0, 0,
+                                         0, 0, 0,
+                                         0, 0, 0 } } });
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/armnnUtils/ParserPrototxtFixture.hpp b/src/armnnUtils/ParserPrototxtFixture.hpp
index be35e46..7ae0742 100644
--- a/src/armnnUtils/ParserPrototxtFixture.hpp
+++ b/src/armnnUtils/ParserPrototxtFixture.hpp
@@ -53,11 +53,17 @@
     template <std::size_t NumOutputDimensions>
     void RunTest(const std::vector<float>& inputData, const std::vector<float>& expectedOutputData);
 
+    /// Executes the network with the given input tensor and checks the result against the given output tensor.
+    /// Calls RunTest with output type of uint8_t for checking comparison operators.
+    template <std::size_t NumOutputDimensions>
+    void RunComparisonTest(const std::map<std::string, std::vector<float>>& inputData,
+                           const std::map<std::string, std::vector<uint8_t>>& expectedOutputData);
+
     /// Executes the network with the given input tensors and checks the results against the given output tensors.
     /// This overload supports multiple inputs and multiple outputs, identified by name.
-    template <std::size_t NumOutputDimensions>
+    template <std::size_t NumOutputDimensions, typename T = float>
     void RunTest(const std::map<std::string, std::vector<float>>& inputData,
-        const std::map<std::string, std::vector<float>>& expectedOutputData);
+                 const std::map<std::string, std::vector<T>>& expectedOutputData);
 
     std::string                                         m_Prototext;
     std::unique_ptr<TParser, void(*)(TParser* parser)>  m_Parser;
@@ -162,15 +168,24 @@
 template<typename TParser>
 template <std::size_t NumOutputDimensions>
 void ParserPrototxtFixture<TParser>::RunTest(const std::vector<float>& inputData,
-    const std::vector<float>& expectedOutputData)
+                                             const std::vector<float>& expectedOutputData)
 {
     RunTest<NumOutputDimensions>({ { m_SingleInputName, inputData } }, { { m_SingleOutputName, expectedOutputData } });
 }
 
 template<typename TParser>
 template <std::size_t NumOutputDimensions>
+void ParserPrototxtFixture<TParser>::RunComparisonTest(const std::map<std::string, std::vector<float>>& inputData,
+                                                       const std::map<std::string, std::vector<uint8_t>>&
+                                                       expectedOutputData)
+{
+    RunTest<NumOutputDimensions, uint8_t>(inputData, expectedOutputData);
+}
+
+template<typename TParser>
+template <std::size_t NumOutputDimensions, typename T>
 void ParserPrototxtFixture<TParser>::RunTest(const std::map<std::string, std::vector<float>>& inputData,
-    const std::map<std::string, std::vector<float>>& expectedOutputData)
+    const std::map<std::string, std::vector<T>>& expectedOutputData)
 {
     using BindingPointInfo = std::pair<armnn::LayerBindingId, armnn::TensorInfo>;
 
@@ -183,12 +198,12 @@
     }
 
     // Allocates storage for the output tensors to be written to and sets up the armnn output tensors.
-    std::map<std::string, boost::multi_array<float, NumOutputDimensions>> outputStorage;
+    std::map<std::string, boost::multi_array<T, NumOutputDimensions>> outputStorage;
     armnn::OutputTensors outputTensors;
     for (auto&& it : expectedOutputData)
     {
         BindingPointInfo bindingInfo = m_Parser->GetNetworkOutputBindingInfo(it.first);
-        outputStorage.emplace(it.first, MakeTensor<float, NumOutputDimensions>(bindingInfo.second));
+        outputStorage.emplace(it.first, MakeTensor<T, NumOutputDimensions>(bindingInfo.second));
         outputTensors.push_back(
             { bindingInfo.first, armnn::Tensor(bindingInfo.second, outputStorage.at(it.first).data()) });
     }
@@ -243,8 +258,15 @@
             }
         }
 
-        auto outputExpected = MakeTensor<float, NumOutputDimensions>(bindingInfo.second, it.second);
-        BOOST_TEST(CompareTensors(outputExpected, outputStorage[it.first]));
+        auto outputExpected = MakeTensor<T, NumOutputDimensions>(bindingInfo.second, it.second);
+        if (std::is_same<T, uint8_t>::value)
+        {
+            BOOST_TEST(CompareTensors(outputExpected, outputStorage[it.first], true));
+        }
+        else
+        {
+            BOOST_TEST(CompareTensors(outputExpected, outputStorage[it.first]));
+        }
     }
 }
 
diff --git a/src/backends/backendsCommon/MakeWorkloadHelper.hpp b/src/backends/backendsCommon/MakeWorkloadHelper.hpp
index 7784cc6..2d54335 100644
--- a/src/backends/backendsCommon/MakeWorkloadHelper.hpp
+++ b/src/backends/backendsCommon/MakeWorkloadHelper.hpp
@@ -38,7 +38,7 @@
 // Makes a workload for one the specified types based on the data type requirements of the tensorinfo.
 // Specify type void as the WorkloadType for unsupported DataType/WorkloadType combos.
 template <typename Float16Workload, typename Float32Workload, typename Uint8Workload, typename Int32Workload,
-    typename QueueDescriptorType, typename... Args>
+          typename BooleanWorkload, typename QueueDescriptorType, typename... Args>
 std::unique_ptr<IWorkload> MakeWorkloadHelper(const QueueDescriptorType& descriptor,
                                               const WorkloadInfo& info,
                                               Args&&... args)
@@ -47,8 +47,10 @@
         info.m_InputTensorInfos[0].GetDataType()
         : info.m_OutputTensorInfos[0].GetDataType();
 
-    BOOST_ASSERT(info.m_InputTensorInfos.empty() || info.m_OutputTensorInfos.empty()
-        || info.m_InputTensorInfos[0].GetDataType() == info.m_OutputTensorInfos[0].GetDataType());
+    BOOST_ASSERT(info.m_InputTensorInfos.empty()  ||
+                 info.m_OutputTensorInfos.empty() ||
+                 ((info.m_InputTensorInfos[0].GetDataType() == info.m_OutputTensorInfos[0].GetDataType()) ||
+                   info.m_OutputTensorInfos[0].GetDataType() == armnn::DataType::Boolean));
 
     switch (dataType)
     {
@@ -60,6 +62,8 @@
             return MakeWorkloadForType<Uint8Workload>::Func(descriptor, info, std::forward<Args>(args)...);
         case DataType::Signed32:
             return MakeWorkloadForType<Int32Workload>::Func(descriptor, info, std::forward<Args>(args)...);
+        case DataType::Boolean:
+            return MakeWorkloadForType<BooleanWorkload>::Func(descriptor, info, std::forward<Args>(args)...);
         default:
             BOOST_ASSERT_MSG(false, "Unknown DataType.");
             return nullptr;
@@ -67,16 +71,18 @@
 }
 
 // Makes a workload for one the specified types based on the data type requirements of the tensorinfo.
-// Calling this method is the equivalent of calling the three typed MakeWorkload method with <FloatWorkload,
-// FloatWorkload, Uint8Workload>.
+// Calling this method is the equivalent of calling the five typed MakeWorkload method with <FloatWorkload,
+// FloatWorkload, Uint8Workload, NullWorkload, NullWorkload>.
 // Specify type void as the WorkloadType for unsupported DataType/WorkloadType combos.
 template <typename FloatWorkload, typename Uint8Workload, typename QueueDescriptorType, typename... Args>
 std::unique_ptr<IWorkload> MakeWorkloadHelper(const QueueDescriptorType& descriptor,
                                               const WorkloadInfo& info,
                                               Args&&... args)
 {
-    return MakeWorkloadHelper<FloatWorkload, FloatWorkload, Uint8Workload, NullWorkload>(descriptor, info,
-       std::forward<Args>(args)...);
+    return MakeWorkloadHelper<FloatWorkload, FloatWorkload, Uint8Workload, NullWorkload, NullWorkload>(
+        descriptor,
+        info,
+        std::forward<Args>(args)...);
 }
 
 } //namespace
diff --git a/src/backends/backendsCommon/Workload.hpp b/src/backends/backendsCommon/Workload.hpp
index 34d1363..4d14adb 100644
--- a/src/backends/backendsCommon/Workload.hpp
+++ b/src/backends/backendsCommon/Workload.hpp
@@ -165,6 +165,19 @@
 using Int32Workload = TypedWorkload<QueueDescriptor, armnn::DataType::Signed32>;
 
 template <typename QueueDescriptor>
+using BooleanWorkload = TypedWorkload<QueueDescriptor, armnn::DataType::Boolean>;
+
+template <typename QueueDescriptor>
+using BaseFloat32ComparisonWorkload = MultiTypedWorkload<QueueDescriptor,
+                                                         armnn::DataType::Float32,
+                                                         armnn::DataType::Boolean>;
+
+template <typename QueueDescriptor>
+using BaseUint8ComparisonWorkload = MultiTypedWorkload<QueueDescriptor,
+                                                       armnn::DataType::QuantisedAsymm8,
+                                                       armnn::DataType::Boolean>;
+
+template <typename QueueDescriptor>
 using Float16ToFloat32Workload = MultiTypedWorkload<QueueDescriptor,
                                                     armnn::DataType::Float16,
                                                     armnn::DataType::Float32>;
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index 05f4e31..9714b02 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -1025,6 +1025,11 @@
                                        "EqualQueueDescriptor",
                                        "first input",
                                        "second input");
+
+    if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
+    {
+        throw InvalidArgumentException("EqualQueueDescriptor: Output tensor type must be Boolean.");
+    }
 }
 
 void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
@@ -1038,6 +1043,11 @@
                                        "GreaterQueueDescriptor",
                                        "first input",
                                        "second input");
+
+    if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
+    {
+        throw InvalidArgumentException("GreaterQueueDescriptor: Output tensor type must be Boolean.");
+    }
 }
 
 void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
diff --git a/src/backends/backendsCommon/test/ArithmeticTestImpl.hpp b/src/backends/backendsCommon/test/ArithmeticTestImpl.hpp
index 1d6cf1d..6f685eb 100644
--- a/src/backends/backendsCommon/test/ArithmeticTestImpl.hpp
+++ b/src/backends/backendsCommon/test/ArithmeticTestImpl.hpp
@@ -17,7 +17,7 @@
 namespace
 {
 
-template<typename armnn::DataType DataType>
+template<armnn::DataType ArmnnTypeInput, armnn::DataType ArmnnTypeOutput>
 INetworkPtr CreateArithmeticNetwork(const std::vector<TensorShape>& inputShapes,
                                     const TensorShape& outputShape,
                                     const LayerType type,
@@ -39,22 +39,25 @@
 
     for (unsigned int i = 0; i < inputShapes.size(); ++i)
     {
-        TensorInfo inputTensorInfo(inputShapes[i], DataType, qScale, qOffset);
+        TensorInfo inputTensorInfo(inputShapes[i], ArmnnTypeInput, qScale, qOffset);
         IConnectableLayer* input = net->AddInputLayer(boost::numeric_cast<LayerBindingId>(i));
         Connect(input, arithmeticLayer, inputTensorInfo, 0, i);
     }
 
-    TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
+    TensorInfo outputTensorInfo(outputShape, ArmnnTypeOutput, qScale, qOffset);
     IConnectableLayer* output = net->AddOutputLayer(0, "output");
     Connect(arithmeticLayer, output, outputTensorInfo, 0, 0);
 
     return net;
 }
 
-template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+template<armnn::DataType ArmnnInputType,
+         armnn::DataType ArmnnOutputType,
+         typename TInput = armnn::ResolveType<ArmnnInputType>,
+         typename TOutput = armnn::ResolveType<ArmnnOutputType>>
 void ArithmeticSimpleEndToEnd(const std::vector<BackendId>& backends,
                               const LayerType type,
-                              const std::vector<T> expectedOutput)
+                              const std::vector<TOutput> expectedOutput)
 {
     using namespace armnn;
 
@@ -62,26 +65,29 @@
     const TensorShape& outputShape = { 2, 2, 2, 2 };
 
     // Builds up the structure of the network
-    INetworkPtr net = CreateArithmeticNetwork<ArmnnType>(inputShapes, outputShape, type);
+    INetworkPtr net = CreateArithmeticNetwork<ArmnnInputType, ArmnnOutputType>(inputShapes, outputShape, type);
 
     BOOST_TEST_CHECKPOINT("create a network");
 
-    const std::vector<T> input0({ 1, 1, 1, 1,  5, 5, 5, 5,
-                                  3, 3, 3, 3,  4, 4, 4, 4 });
+    const std::vector<TInput> input0({ 1, 1, 1, 1,  5, 5, 5, 5,
+                                       3, 3, 3, 3,  4, 4, 4, 4 });
 
-    const std::vector<T> input1({ 1, 1, 1, 1,  3, 3, 3, 3,
-                                  5, 5, 5, 5,  4, 4, 4, 4 });
+    const std::vector<TInput> input1({ 1, 1, 1, 1,  3, 3, 3, 3,
+                                       5, 5, 5, 5,  4, 4, 4, 4 });
 
-    std::map<int, std::vector<T>> inputTensorData = {{ 0, input0 }, { 1, input1 }};
-    std::map<int, std::vector<T>> expectedOutputData = {{ 0, expectedOutput }};
+    std::map<int, std::vector<TInput>> inputTensorData = {{ 0, input0 }, { 1, input1 }};
+    std::map<int, std::vector<TOutput>> expectedOutputData = {{ 0, expectedOutput }};
 
-    EndToEndLayerTestImpl<T>(move(net), inputTensorData, expectedOutputData, backends);
+    EndToEndLayerTestImpl<TInput, TOutput>(move(net), inputTensorData, expectedOutputData, backends);
 }
 
-template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+template<armnn::DataType ArmnnInputType,
+         armnn::DataType ArmnnOutputType,
+         typename TInput = armnn::ResolveType<ArmnnInputType>,
+         typename TOutput = armnn::ResolveType<ArmnnOutputType>>
 void ArithmeticBroadcastEndToEnd(const std::vector<BackendId>& backends,
                                  const LayerType type,
-                                 const std::vector<T> expectedOutput)
+                                 const std::vector<TOutput> expectedOutput)
 {
     using namespace armnn;
 
@@ -89,19 +95,19 @@
     const TensorShape& outputShape = { 1, 2, 2, 3 };
 
     // Builds up the structure of the network
-    INetworkPtr net = CreateArithmeticNetwork<ArmnnType>(inputShapes, outputShape, type);
+    INetworkPtr net = CreateArithmeticNetwork<ArmnnInputType, ArmnnOutputType>(inputShapes, outputShape, type);
 
     BOOST_TEST_CHECKPOINT("create a network");
 
-    const std::vector<T> input0({ 1, 2, 3, 1, 0, 6,
-                                  7, 8, 9, 10, 11, 12 });
+    const std::vector<TInput> input0({ 1, 2, 3, 1, 0, 6,
+                                       7, 8, 9, 10, 11, 12 });
 
-    const std::vector<T> input1({ 1, 1, 3 });
+    const std::vector<TInput> input1({ 1, 1, 3 });
 
-    std::map<int, std::vector<T>> inputTensorData = {{ 0, input0 }, { 1, input1 }};
-    std::map<int, std::vector<T>> expectedOutputData = {{ 0, expectedOutput }};
+    std::map<int, std::vector<TInput>> inputTensorData = {{ 0, input0 }, { 1, input1 }};
+    std::map<int, std::vector<TOutput>> expectedOutputData = {{ 0, expectedOutput }};
 
-    EndToEndLayerTestImpl<T>(move(net), inputTensorData, expectedOutputData, backends);
+    EndToEndLayerTestImpl<TInput, TOutput>(move(net), inputTensorData, expectedOutputData, backends);
 }
 
 } // anonymous namespace
diff --git a/src/backends/backendsCommon/test/EndToEndTestImpl.hpp b/src/backends/backendsCommon/test/EndToEndTestImpl.hpp
index 15a3937..7d2b091 100644
--- a/src/backends/backendsCommon/test/EndToEndTestImpl.hpp
+++ b/src/backends/backendsCommon/test/EndToEndTestImpl.hpp
@@ -102,10 +102,10 @@
     );
 }
 
-template<typename T>
+template<typename TInput, typename TOutput>
 void EndToEndLayerTestImpl(INetworkPtr network,
-                           const std::map<int, std::vector<T>>& inputTensorData,
-                           const std::map<int, std::vector<T>>& expectedOutputData,
+                           const std::map<int, std::vector<TInput>>& inputTensorData,
+                           const std::map<int, std::vector<TOutput>>& expectedOutputData,
                            std::vector<BackendId> backends)
 {
     // Create runtime in which test will run
@@ -128,10 +128,10 @@
     }
     OutputTensors outputTensors;
     outputTensors.reserve(expectedOutputData.size());
-    std::map<int, std::vector<T>> outputStorage;
+    std::map<int, std::vector<TOutput>> outputStorage;
     for (auto&& it : expectedOutputData)
     {
-        std::vector<T> out(it.second.size());
+        std::vector<TOutput> out(it.second.size());
         outputStorage.emplace(it.first, out);
         outputTensors.push_back({it.first,
                                  Tensor(runtime->GetOutputTensorInfo(netId, it.first),
@@ -144,7 +144,7 @@
     // Checks the results.
     for (auto&& it : expectedOutputData)
     {
-        std::vector<T> out = outputStorage.at(it.first);
+        std::vector<TOutput> out = outputStorage.at(it.first);
         BOOST_TEST(it.second == out);
     }
 }
diff --git a/src/backends/backendsCommon/test/LayerTests.cpp b/src/backends/backendsCommon/test/LayerTests.cpp
index 95fa50b..6060b30 100644
--- a/src/backends/backendsCommon/test/LayerTests.cpp
+++ b/src/backends/backendsCommon/test/LayerTests.cpp
@@ -1783,66 +1783,98 @@
 }
 
 namespace {
-    template <typename Descriptor, armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
-    LayerTestResult<T, 4> ElementwiseTestHelper
-        (armnn::IWorkloadFactory & workloadFactory,
-         const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,
-         const unsigned int shape0[4], std::vector<T> values0,
-         const unsigned int shape1[4], std::vector<T> values1,
-         const unsigned int outShape[4], std::vector<T> outValues,
-         float qScale = 0.0f, int qOffset = 0)
+
+template <typename Descriptor,
+          armnn::DataType ArmnnTypeInput,
+          armnn::DataType ArmnnTypeOutput,
+          typename TInput = armnn::ResolveType<ArmnnTypeInput>,
+          typename TOutput = armnn::ResolveType<ArmnnTypeOutput>>
+LayerTestResult<TOutput, 4> ElementwiseTestHelper(
+    armnn::IWorkloadFactory & workloadFactory,
+    const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,
+    const unsigned int shape0[4], std::vector<TInput> values0,
+    const unsigned int shape1[4], std::vector<TInput> values1,
+    const unsigned int outShape[4], std::vector<TOutput> outValues,
+    float qScale = 0.0f, int qOffset = 0)
+{
+    const size_t dimensionCount = 4;
+    armnn::TensorInfo inputTensorInfo0{dimensionCount, shape0, ArmnnTypeInput};
+    armnn::TensorInfo inputTensorInfo1{dimensionCount, shape1, ArmnnTypeInput};
+    armnn::TensorInfo outputTensorInfo{dimensionCount, outShape, ArmnnTypeOutput};
+
+    auto input0 = MakeTensor<TInput, 4>(inputTensorInfo0, values0);
+    auto input1 = MakeTensor<TInput, 4>(inputTensorInfo1, values1);
+
+    if (armnn::IsQuantizedType<TInput>())
     {
-        const size_t dimensionCount = 4;
-        armnn::TensorInfo inputTensorInfo0{dimensionCount, shape0, ArmnnType};
-        armnn::TensorInfo inputTensorInfo1{dimensionCount, shape1, ArmnnType};
-        armnn::TensorInfo outputTensorInfo{dimensionCount, outShape, ArmnnType};
+        inputTensorInfo0.SetQuantizationScale(qScale);
+        inputTensorInfo0.SetQuantizationOffset(qOffset);
 
-        auto input0 = MakeTensor<T, 4>(inputTensorInfo0, values0);
-        auto input1 = MakeTensor<T, 4>(inputTensorInfo1, values1);
+        inputTensorInfo1.SetQuantizationScale(qScale);
+        inputTensorInfo1.SetQuantizationOffset(qOffset);
 
-        if (armnn::IsQuantizedType<T>())
-        {
-            inputTensorInfo0.SetQuantizationScale(qScale);
-            inputTensorInfo0.SetQuantizationOffset(qOffset);
-
-            inputTensorInfo1.SetQuantizationScale(qScale);
-            inputTensorInfo1.SetQuantizationOffset(qOffset);
-
-            outputTensorInfo.SetQuantizationScale(qScale);
-            outputTensorInfo.SetQuantizationOffset(qOffset);
-        }
-
-        LayerTestResult<T,4> ret(outputTensorInfo);
-
-        std::unique_ptr<armnn::ITensorHandle> inputHandle0 = workloadFactory.CreateTensorHandle(inputTensorInfo0);
-        std::unique_ptr<armnn::ITensorHandle> inputHandle1 = workloadFactory.CreateTensorHandle(inputTensorInfo1);
-        std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
-
-        Descriptor data;
-        armnn::WorkloadInfo info;
-        AddInputToWorkload(data, info, inputTensorInfo0, inputHandle0.get());
-        AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
-        AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
-        auto workload = CreateWorkload<Descriptor>(workloadFactory, info, data);
-
-        inputHandle0->Allocate();
-        inputHandle1->Allocate();
-        outputHandle->Allocate();
-
-        CopyDataToITensorHandle(inputHandle0.get(), &input0[0][0][0][0]);
-        CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0][0]);
-
-        ExecuteWorkload(*workload, memoryManager);
-
-        CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
-
-        ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outValues);
-        return ret;
+        outputTensorInfo.SetQuantizationScale(qScale);
+        outputTensorInfo.SetQuantizationOffset(qOffset);
     }
+
+    LayerTestResult<TOutput,4> ret(outputTensorInfo);
+
+    if(ArmnnTypeOutput == armnn::DataType::Boolean)
+    {
+        ret.compareBoolean = true;
+    }
+
+    std::unique_ptr<armnn::ITensorHandle> inputHandle0 = workloadFactory.CreateTensorHandle(inputTensorInfo0);
+    std::unique_ptr<armnn::ITensorHandle> inputHandle1 = workloadFactory.CreateTensorHandle(inputTensorInfo1);
+    std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
+
+    Descriptor data;
+    armnn::WorkloadInfo info;
+    AddInputToWorkload(data, info, inputTensorInfo0, inputHandle0.get());
+    AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
+    AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
+    auto workload = CreateWorkload<Descriptor>(workloadFactory, info, data);
+
+    inputHandle0->Allocate();
+    inputHandle1->Allocate();
+    outputHandle->Allocate();
+
+    CopyDataToITensorHandle(inputHandle0.get(), &input0[0][0][0][0]);
+    CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0][0]);
+
+    ExecuteWorkload(*workload, memoryManager);
+
+    CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
+
+    ret.outputExpected = MakeTensor<TOutput, 4>(outputTensorInfo, outValues);
+    return ret;
 }
 
-LayerTestResult<float, 4> EqualSimpleTest(armnn::IWorkloadFactory& workloadFactory,
-                                          const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
+template <typename Descriptor, armnn::DataType ArmnnT, typename T = armnn::ResolveType<ArmnnT>>
+LayerTestResult<T, 4> ElementwiseTestHelper(
+    armnn::IWorkloadFactory & workloadFactory,
+    const armnn::IBackendInternal::IMemoryManagerSharedPtr & memoryManager,
+    const unsigned int shape0[4], std::vector<T> values0,
+    const unsigned int shape1[4], std::vector<T> values1,
+    const unsigned int outShape[4], std::vector<T> outValues,
+    float qScale = 0.0f, int qOffset = 0)
+{
+    return ElementwiseTestHelper<Descriptor, ArmnnT, ArmnnT>
+        (workloadFactory,
+         memoryManager,
+         shape0,
+         values0,
+         shape1,
+         values1,
+         outShape,
+         outValues,
+         qScale,
+         qOffset);
+}
+}
+
+LayerTestResult<uint8_t, 4> EqualSimpleTest(armnn::IWorkloadFactory& workloadFactory,
+                                            const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
 {
     const unsigned int width = 2;
     const unsigned int height = 2;
@@ -1857,10 +1889,10 @@
     std::vector<float> input1({ 1, 1, 1, 1,  3, 3, 3, 3,
                                 5, 5, 5, 5,  4, 4, 4, 4 });
 
-    std::vector<float> output({ 1, 1, 1, 1,  0, 0, 0, 0,
-                                0, 0, 0, 0,  1, 1, 1, 1 });
+    std::vector<uint8_t> output({ 1, 1, 1, 1,  0, 0, 0, 0,
+                                  0, 0, 0, 0,  1, 1, 1, 1 });
 
-    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::Float32>(
+    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::Float32, armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape,
@@ -1871,7 +1903,7 @@
         output);
 }
 
-LayerTestResult<float, 4> EqualBroadcast1ElementTest(
+LayerTestResult<uint8_t, 4> EqualBroadcast1ElementTest(
         armnn::IWorkloadFactory& workloadFactory,
         const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
 {
@@ -1881,9 +1913,9 @@
     unsigned int shape1[] = { 1, 1, 1, 1 };
     std::vector<float> input1({ 1 });
 
-    std::vector<float> output({ 1, 0, 0, 0, 0, 0, 0, 0});
+    std::vector<uint8_t> output({ 1, 0, 0, 0, 0, 0, 0, 0});
 
-    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::Float32>(
+    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::Float32, armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -1894,7 +1926,7 @@
         output);
 }
 
-LayerTestResult<float, 4> EqualBroadcast1DVectorTest(
+LayerTestResult<uint8_t, 4> EqualBroadcast1DVectorTest(
         armnn::IWorkloadFactory& workloadFactory,
         const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
 {
@@ -1906,10 +1938,10 @@
 
     std::vector<float> input1({ 1, 2, 3});
 
-    std::vector<float> output({ 1, 1, 1, 0, 0, 0,
-                                0, 0, 0, 0, 0, 0 });
+    std::vector<uint8_t> output({ 1, 1, 1, 0, 0, 0,
+                                  0, 0, 0, 0, 0, 0 });
 
-    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::Float32>(
+    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::Float32, armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -1928,7 +1960,7 @@
 
     // See dequantized values to the right.
     std::vector<uint8_t> input0({ 1, 1, 1, 1, 6, 6, 6, 6,
-                                  3, 3, 3, 3, 5, 5, 5, 5 });
+                                  3, 3, 3, 3, 7, 7, 7, 7 });
 
     std::vector<uint8_t> input1({ 2, 2, 2, 2, 6, 6, 6, 6,
                                   3, 3, 3, 3, 5, 5, 5, 5 });
@@ -1936,7 +1968,9 @@
     std::vector<uint8_t> output({ 0, 0, 0, 0, 1, 1, 1, 1,
                                   1, 1, 1, 1, 0, 0, 0, 0 });
 
-    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::QuantisedAsymm8>(
+    return ElementwiseTestHelper<armnn::EqualQueueDescriptor,
+                                 armnn::DataType::QuantisedAsymm8,
+                                 armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape,
@@ -1964,7 +1998,9 @@
     std::vector<uint8_t> output({ 1, 0, 0, 0, 0, 0,
                                   0, 0, 0, 0, 0, 0 });
 
-    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::QuantisedAsymm8>(
+    return ElementwiseTestHelper<armnn::EqualQueueDescriptor,
+                                 armnn::DataType::QuantisedAsymm8,
+                                 armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -1992,7 +2028,9 @@
     std::vector<uint8_t> output({ 1, 0, 1, 0, 0, 0,
                                   0, 0, 0, 0, 0, 0 });
 
-    return ElementwiseTestHelper<armnn::EqualQueueDescriptor, armnn::DataType::QuantisedAsymm8>(
+    return ElementwiseTestHelper<armnn::EqualQueueDescriptor,
+                                 armnn::DataType::QuantisedAsymm8,
+                                 armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -2005,7 +2043,7 @@
         0);
 }
 
-LayerTestResult<float, 4> GreaterSimpleTest(armnn::IWorkloadFactory& workloadFactory,
+LayerTestResult<uint8_t, 4> GreaterSimpleTest(armnn::IWorkloadFactory& workloadFactory,
                                             const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
 {
     const unsigned int width = 2;
@@ -2021,10 +2059,10 @@
     std::vector<float> input1({ 1, 1, 1, 1,  3, 3, 3, 3,
                                 5, 5, 5, 5,  4, 4, 4, 4 });
 
-    std::vector<float> output({ 0, 0, 0, 0,  1, 1, 1, 1,
-                                0, 0, 0, 0,  0, 0, 0, 0 });
+    std::vector<uint8_t> output({ 0, 0, 0, 0,  1, 1, 1, 1,
+                                  0, 0, 0, 0,  0, 0, 0, 0 });
 
-    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::Float32>(
+    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::Float32, armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape,
@@ -2035,7 +2073,7 @@
         output);
 }
 
-LayerTestResult<float, 4> GreaterBroadcast1ElementTest(
+LayerTestResult<uint8_t, 4> GreaterBroadcast1ElementTest(
         armnn::IWorkloadFactory& workloadFactory,
         const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
 {
@@ -2045,9 +2083,9 @@
     unsigned int shape1[] = { 1, 1, 1, 1 };
     std::vector<float> input1({ 1 });
 
-    std::vector<float> output({ 0, 1, 1, 1, 1, 1, 1, 1});
+    std::vector<uint8_t> output({ 0, 1, 1, 1, 1, 1, 1, 1});
 
-    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::Float32>(
+    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::Float32, armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -2058,7 +2096,7 @@
         output);
 }
 
-LayerTestResult<float, 4> GreaterBroadcast1DVectorTest(
+LayerTestResult<uint8_t, 4> GreaterBroadcast1DVectorTest(
         armnn::IWorkloadFactory& workloadFactory,
         const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
 {
@@ -2070,10 +2108,10 @@
 
     std::vector<float> input1({ 1, 3, 2});
 
-    std::vector<float> output({ 0, 0, 1, 1, 1, 1,
-                                1, 1, 1, 1, 1, 1 });
+    std::vector<uint8_t> output({ 0, 0, 1, 1, 1, 1,
+                                  1, 1, 1, 1, 1, 1 });
 
-    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::Float32>(
+    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::Float32, armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -2100,7 +2138,9 @@
     std::vector<uint8_t> output({ 0, 0, 0, 0, 0, 0, 0, 0,
                                   1, 1, 1, 1, 0, 0, 0, 0 });
 
-    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::QuantisedAsymm8>(
+    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor,
+                                 armnn::DataType::QuantisedAsymm8,
+                                 armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape,
@@ -2128,7 +2168,9 @@
     std::vector<uint8_t> output({ 0, 1, 1, 1, 1, 1,
                                   1, 1, 1, 1, 1, 1 });
 
-    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::QuantisedAsymm8>(
+    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor,
+                                 armnn::DataType::QuantisedAsymm8,
+                                 armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -2156,7 +2198,9 @@
     std::vector<uint8_t> output({ 0, 1, 0, 1, 1, 1,
                                   1, 1, 1, 1, 1, 1 });
 
-    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor, armnn::DataType::QuantisedAsymm8>(
+    return ElementwiseTestHelper<armnn::GreaterQueueDescriptor,
+                                 armnn::DataType::QuantisedAsymm8,
+                                 armnn::DataType::Boolean>(
         workloadFactory,
         memoryManager,
         shape0,
@@ -2235,7 +2279,7 @@
     std::vector<float> input1({ 1, 2, 3});
 
     std::vector<float> output({ 1, 2, 3, 4, 5, 6,
-                                  7, 8, 9, 10, 11, 12 });
+                                7, 8, 9, 10, 11, 12 });
 
     return ElementwiseTestHelper<armnn::MaximumQueueDescriptor, armnn::DataType::Float32>(
         workloadFactory,
diff --git a/src/backends/backendsCommon/test/LayerTests.hpp b/src/backends/backendsCommon/test/LayerTests.hpp
index 16fe432..05d510e 100644
--- a/src/backends/backendsCommon/test/LayerTests.hpp
+++ b/src/backends/backendsCommon/test/LayerTests.hpp
@@ -47,11 +47,13 @@
         output.resize(shape);
         outputExpected.resize(shape);
         supported = true;
+        compareBoolean = false;
     }
 
     boost::multi_array<T, n> output;
     boost::multi_array<T, n> outputExpected;
     bool supported;
+    bool compareBoolean;
 };
 
 LayerTestResult<float, 4> SimpleConvolution2d3x5Test(
@@ -909,15 +911,15 @@
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
     bool useSubtensor);
 
-LayerTestResult<float, 4> EqualSimpleTest(
+LayerTestResult<uint8_t, 4> EqualSimpleTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
-LayerTestResult<float, 4> EqualBroadcast1ElementTest(
+LayerTestResult<uint8_t, 4> EqualBroadcast1ElementTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
-LayerTestResult<float, 4> EqualBroadcast1DVectorTest(
+LayerTestResult<uint8_t, 4> EqualBroadcast1DVectorTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
@@ -933,15 +935,15 @@
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
-LayerTestResult<float, 4> GreaterSimpleTest(
+LayerTestResult<uint8_t, 4> GreaterSimpleTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
-LayerTestResult<float, 4> GreaterBroadcast1ElementTest(
+LayerTestResult<uint8_t, 4> GreaterBroadcast1ElementTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
-LayerTestResult<float, 4> GreaterBroadcast1DVectorTest(
+LayerTestResult<uint8_t, 4> GreaterBroadcast1DVectorTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
 
diff --git a/src/backends/backendsCommon/test/MergerTestImpl.hpp b/src/backends/backendsCommon/test/MergerTestImpl.hpp
index 2bdfe28..ec42b09 100644
--- a/src/backends/backendsCommon/test/MergerTestImpl.hpp
+++ b/src/backends/backendsCommon/test/MergerTestImpl.hpp
@@ -110,7 +110,7 @@
     std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }, { 1,inputData }};
     std::map<int, std::vector<T>> expectedOutputData = {{ 0,expectedOutput }};
 
-    EndToEndLayerTestImpl<T>(move(net), inputTensorData, expectedOutputData, backends);
+    EndToEndLayerTestImpl<T, T>(move(net), inputTensorData, expectedOutputData, backends);
 }
 
 template<armnn::DataType ArmnnType>
diff --git a/src/backends/cl/ClLayerSupport.cpp b/src/backends/cl/ClLayerSupport.cpp
index 3e35f9d..410cb04 100644
--- a/src/backends/cl/ClLayerSupport.cpp
+++ b/src/backends/cl/ClLayerSupport.cpp
@@ -122,6 +122,7 @@
                                       floatFuncPtr,
                                       uint8FuncPtr,
                                       &FalseFunc<>,
+                                      &FalseFunc<>,
                                       std::forward<Params>(params)...);
 }
 
@@ -267,7 +268,8 @@
                                          &FalseFuncF16<>,
                                          &TrueFunc<>,
                                          &FalseFuncU8<>,
-                                         &FalseFuncI32<>);
+                                         &FalseFuncI32<>,
+                                         &FalseFuncU8<>);
 }
 
 bool ClLayerSupport::IsFullyConnectedSupported(const TensorInfo& input,
@@ -453,10 +455,14 @@
 bool ClLayerSupport::IsOutputSupported(const TensorInfo& output,
                                        Optional<std::string&> reasonIfUnsupported) const
 {
-    return IsSupportedForDataTypeCl(reasonIfUnsupported,
-                                    output.GetDataType(),
-                                    &TrueFunc<>,
-                                    &TrueFunc<>);
+    return IsClBackendSupported(reasonIfUnsupported) &&
+           IsSupportedForDataTypeGeneric(reasonIfUnsupported,
+                                         output.GetDataType(),
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &FalseFuncI32<>,
+                                         &TrueFunc<>);
 }
 
 bool ClLayerSupport::IsPadSupported(const TensorInfo& input,
diff --git a/src/backends/cl/ClWorkloadFactory.cpp b/src/backends/cl/ClWorkloadFactory.cpp
index 71c1b89..7a53257 100644
--- a/src/backends/cl/ClWorkloadFactory.cpp
+++ b/src/backends/cl/ClWorkloadFactory.cpp
@@ -126,7 +126,8 @@
 std::unique_ptr<IWorkload> ClWorkloadFactory::CreateOutput(const OutputQueueDescriptor& descriptor,
                                                            const WorkloadInfo& info) const
 {
-    return MakeWorkload<CopyMemGenericWorkload, CopyMemGenericWorkload>(descriptor, info);
+    return MakeWorkloadHelper<CopyMemGenericWorkload, CopyMemGenericWorkload, CopyMemGenericWorkload, NullWorkload,
+        CopyMemGenericWorkload>(descriptor, info);
 }
 
 std::unique_ptr<IWorkload> ClWorkloadFactory::CreateActivation(const ActivationQueueDescriptor& descriptor,
diff --git a/src/backends/neon/NeonLayerSupport.cpp b/src/backends/neon/NeonLayerSupport.cpp
index 2f83c8f..9db7354 100644
--- a/src/backends/neon/NeonLayerSupport.cpp
+++ b/src/backends/neon/NeonLayerSupport.cpp
@@ -72,6 +72,7 @@
                                          floatFuncPtr,
                                          uint8FuncPtr,
                                          &FalseFunc<>,
+                                         &FalseFunc<>,
                                          std::forward<Params>(params)...);
 }
 
@@ -214,7 +215,8 @@
                                          &FalseFuncF16<>,
                                          &TrueFunc<>,
                                          &FalseFuncU8<>,
-                                         &FalseFuncI32<>);
+                                         &FalseFuncI32<>,
+                                         &FalseFuncU8<>);
 }
 
 bool NeonLayerSupport::IsFullyConnectedSupported(const TensorInfo& input,
@@ -344,10 +346,14 @@
 bool NeonLayerSupport::IsOutputSupported(const TensorInfo& output,
                                          Optional<std::string&> reasonIfUnsupported) const
 {
-    return IsSupportedForDataTypeNeon(reasonIfUnsupported,
-                                      output.GetDataType(),
-                                      &TrueFunc<>,
-                                      &TrueFunc<>);
+    return IsNeonBackendSupported(reasonIfUnsupported) &&
+           IsSupportedForDataTypeGeneric(reasonIfUnsupported,
+                                         output.GetDataType(),
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &FalseFuncI32<>,
+                                         &TrueFunc<>);
 }
 
 bool NeonLayerSupport::IsPermuteSupported(const TensorInfo& input,
diff --git a/src/backends/neon/NeonTensorHandle.hpp b/src/backends/neon/NeonTensorHandle.hpp
index 7206b6f..b972043 100644
--- a/src/backends/neon/NeonTensorHandle.hpp
+++ b/src/backends/neon/NeonTensorHandle.hpp
@@ -94,6 +94,7 @@
                 armcomputetensorutils::CopyArmComputeITensorData(this->GetTensor(),
                                                                  static_cast<float*>(memory));
                 break;
+            case arm_compute::DataType::U8:
             case arm_compute::DataType::QASYMM8:
                 armcomputetensorutils::CopyArmComputeITensorData(this->GetTensor(),
                                                                  static_cast<uint8_t*>(memory));
@@ -114,6 +115,7 @@
                 armcomputetensorutils::CopyArmComputeITensorData(static_cast<const float*>(memory),
                                                                  this->GetTensor());
                 break;
+            case arm_compute::DataType::U8:
             case arm_compute::DataType::QASYMM8:
                 armcomputetensorutils::CopyArmComputeITensorData(static_cast<const uint8_t*>(memory),
                                                                  this->GetTensor());
@@ -181,6 +183,7 @@
                 armcomputetensorutils::CopyArmComputeITensorData(this->GetTensor(),
                                                                  static_cast<float*>(memory));
                 break;
+            case arm_compute::DataType::U8:
             case arm_compute::DataType::QASYMM8:
                 armcomputetensorutils::CopyArmComputeITensorData(this->GetTensor(),
                                                                  static_cast<uint8_t*>(memory));
@@ -201,6 +204,7 @@
                 armcomputetensorutils::CopyArmComputeITensorData(static_cast<const float*>(memory),
                                                                  this->GetTensor());
                 break;
+            case arm_compute::DataType::U8:
             case arm_compute::DataType::QASYMM8:
                 armcomputetensorutils::CopyArmComputeITensorData(static_cast<const uint8_t*>(memory),
                                                                  this->GetTensor());
diff --git a/src/backends/neon/NeonWorkloadFactory.cpp b/src/backends/neon/NeonWorkloadFactory.cpp
index e7fac97..e8a00d6 100644
--- a/src/backends/neon/NeonWorkloadFactory.cpp
+++ b/src/backends/neon/NeonWorkloadFactory.cpp
@@ -91,7 +91,8 @@
 std::unique_ptr<IWorkload> NeonWorkloadFactory::CreateOutput(const OutputQueueDescriptor& descriptor,
                                                              const WorkloadInfo&        info) const
 {
-    return MakeWorkloadHelper<CopyMemGenericWorkload, CopyMemGenericWorkload>(descriptor, info);
+    return MakeWorkloadHelper<CopyMemGenericWorkload, CopyMemGenericWorkload,
+                              CopyMemGenericWorkload, NullWorkload, CopyMemGenericWorkload>(descriptor, info);
 }
 
 std::unique_ptr<IWorkload> NeonWorkloadFactory::CreateActivation(const ActivationQueueDescriptor& descriptor,
diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp
index 45f108c..78e44bd 100644
--- a/src/backends/reference/RefLayerSupport.cpp
+++ b/src/backends/reference/RefLayerSupport.cpp
@@ -35,6 +35,7 @@
                                          floatFuncPtr,
                                          uint8FuncPtr,
                                          &FalseFunc<Params...>,
+                                         &FalseFunc<Params...>,
                                          std::forward<Params>(params)...);
 }
 
@@ -111,7 +112,8 @@
                                          &FalseFunc<>,
                                          &TrueFunc<>,
                                          &TrueFunc<>,
-                                         &TrueFunc<>);
+                                         &TrueFunc<>,
+                                         &FalseFunc<>);
 }
 
 bool RefLayerSupport::IsConvertFp16ToFp32Supported(const TensorInfo& input,
@@ -123,13 +125,15 @@
                                           &TrueFunc<>,
                                           &FalseInputFuncF32<>,
                                           &FalseFuncU8<>,
-                                          &FalseFuncI32<>) &&
+                                          &FalseFuncI32<>,
+                                          &FalseFuncU8<>) &&
             IsSupportedForDataTypeGeneric(reasonIfUnsupported,
                                           output.GetDataType(),
                                           &FalseOutputFuncF16<>,
                                           &TrueFunc<>,
                                           &FalseFuncU8<>,
-                                          &FalseFuncI32<>));
+                                          &FalseFuncI32<>,
+                                          &FalseFuncU8<>));
 }
 
 bool RefLayerSupport::IsConvertFp32ToFp16Supported(const TensorInfo& input,
@@ -141,13 +145,15 @@
                                           &FalseInputFuncF16<>,
                                           &TrueFunc<>,
                                           &FalseFuncU8<>,
-                                          &FalseFuncI32<>) &&
+                                          &FalseFuncI32<>,
+                                          &FalseFuncU8<>) &&
             IsSupportedForDataTypeGeneric(reasonIfUnsupported,
                                           output.GetDataType(),
                                           &TrueFunc<>,
                                           &FalseOutputFuncF32<>,
                                           &FalseFuncU8<>,
-                                          &FalseFuncI32<>));
+                                          &FalseFuncI32<>,
+                                          &FalseFuncU8<>));
 }
 
 bool RefLayerSupport::IsConvolution2dSupported(const TensorInfo& input,
@@ -415,10 +421,13 @@
                                          Optional<std::string &> reasonIfUnsupported) const
 {
     ignore_unused(output);
-    return IsSupportedForDataTypeRef(reasonIfUnsupported,
-                                     input.GetDataType(),
-                                     &TrueFunc<>,
-                                     &TrueFunc<>);
+    return IsSupportedForDataTypeGeneric(reasonIfUnsupported,
+                                         input.GetDataType(),
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &FalseFuncI32<>,
+                                         &TrueFunc<>);
 }
 
 bool RefLayerSupport::IsMinimumSupported(const TensorInfo& input0,
@@ -463,10 +472,13 @@
 bool RefLayerSupport::IsOutputSupported(const TensorInfo& output,
                                         Optional<std::string&> reasonIfUnsupported) const
 {
-    return IsSupportedForDataTypeRef(reasonIfUnsupported,
-                                     output.GetDataType(),
-                                     &TrueFunc<>,
-                                     &TrueFunc<>);
+    return IsSupportedForDataTypeGeneric(reasonIfUnsupported,
+                                         output.GetDataType(),
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &TrueFunc<>,
+                                         &FalseFuncI32<>,
+                                         &TrueFunc<>);
 }
 
 bool RefLayerSupport::IsPadSupported(const TensorInfo& input,
diff --git a/src/backends/reference/RefWorkloadFactory.cpp b/src/backends/reference/RefWorkloadFactory.cpp
index b112e9d..75a9efd 100644
--- a/src/backends/reference/RefWorkloadFactory.cpp
+++ b/src/backends/reference/RefWorkloadFactory.cpp
@@ -24,7 +24,8 @@
 std::unique_ptr<IWorkload> RefWorkloadFactory::MakeWorkload(const QueueDescriptorType& descriptor,
     const WorkloadInfo& info) const
 {
-    return armnn::MakeWorkloadHelper<NullWorkload, F32Workload, U8Workload, NullWorkload>(descriptor, info);
+    return armnn::MakeWorkloadHelper<NullWorkload, F32Workload, U8Workload, NullWorkload, NullWorkload>(descriptor,
+                                                                                                        info);
 }
 
 RefWorkloadFactory::RefWorkloadFactory()
@@ -90,7 +91,8 @@
         throw InvalidArgumentException("RefWorkloadFactory::CreateOutput: data input and output differ in byte count.");
     }
 
-    return MakeWorkload<CopyMemGenericWorkload, CopyMemGenericWorkload>(descriptor, info);
+    return MakeWorkloadHelper<CopyMemGenericWorkload, CopyMemGenericWorkload,
+                              CopyMemGenericWorkload, NullWorkload, CopyMemGenericWorkload>(descriptor, info);
 }
 
 std::unique_ptr<IWorkload> RefWorkloadFactory::CreateActivation(const ActivationQueueDescriptor& descriptor,
@@ -127,7 +129,7 @@
                                                                     const WorkloadInfo&           info) const
 {
     return MakeWorkloadHelper<RefPermuteFloat16Workload, RefPermuteFloat32Workload, RefPermuteUint8Workload,
-        NullWorkload>(descriptor, info);
+        NullWorkload, NullWorkload>(descriptor, info);
 }
 
 std::unique_ptr<armnn::IWorkload> RefWorkloadFactory::CreatePooling2d(const Pooling2dQueueDescriptor& descriptor,
@@ -206,7 +208,7 @@
     const WorkloadInfo& info) const
 {
     return MakeWorkloadHelper<NullWorkload, RefConstantFloat32Workload, RefConstantUint8Workload,
-        RefConstantInt32Workload>(descriptor, info);
+        RefConstantInt32Workload, NullWorkload>(descriptor, info);
 }
 
 std::unique_ptr<IWorkload> RefWorkloadFactory::CreateReshape(const ReshapeQueueDescriptor& descriptor,
diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk
index 763f26e..3ee0791 100644
--- a/src/backends/reference/backend.mk
+++ b/src/backends/reference/backend.mk
@@ -28,6 +28,7 @@
         workloads/RefBatchNormalizationUint8Workload.cpp \
         workloads/RefBatchToSpaceNdFloat32Workload.cpp \
         workloads/RefBatchToSpaceNdUint8Workload.cpp \
+        workloads/RefComparisonWorkload.cpp \
         workloads/RefConstantWorkload.cpp \
         workloads/RefConvertFp16ToFp32Workload.cpp \
         workloads/RefConvertFp32ToFp16Workload.cpp \
diff --git a/src/backends/reference/test/RefEndToEndTests.cpp b/src/backends/reference/test/RefEndToEndTests.cpp
index 330f406..802167a 100644
--- a/src/backends/reference/test/RefEndToEndTests.cpp
+++ b/src/backends/reference/test/RefEndToEndTests.cpp
@@ -315,18 +315,22 @@
 
 BOOST_AUTO_TEST_CASE(RefEqualSimpleEndToEndTest)
 {
-    const std::vector<float > expectedOutput({ 1, 1, 1, 1,  0, 0, 0, 0,
-                                               0, 0, 0, 0,  1, 1, 1, 1 });
+    const std::vector<uint8_t> expectedOutput({ 1, 1, 1, 1,  0, 0, 0, 0,
+                                                0, 0, 0, 0,  1, 1, 1, 1 });
 
-    ArithmeticSimpleEndToEnd<armnn::DataType::Float32>(defaultBackends, LayerType::Equal, expectedOutput);
+    ArithmeticSimpleEndToEnd<armnn::DataType::Float32, armnn::DataType::Boolean>(defaultBackends,
+                                                                                 LayerType::Equal,
+                                                                                 expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefGreaterSimpleEndToEndTest)
 {
-    const std::vector<float> expectedOutput({ 0, 0, 0, 0,  1, 1, 1, 1,
-                                              0, 0, 0, 0,  0, 0, 0, 0 });
+    const std::vector<uint8_t> expectedOutput({ 0, 0, 0, 0,  1, 1, 1, 1,
+                                                0, 0, 0, 0,  0, 0, 0, 0 });
 
-    ArithmeticSimpleEndToEnd<armnn::DataType::Float32>(defaultBackends, LayerType::Greater, expectedOutput);
+    ArithmeticSimpleEndToEnd<armnn::DataType::Float32, armnn::DataType::Boolean>(defaultBackends,
+                                                                                 LayerType::Greater,
+                                                                                 expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefEqualSimpleEndToEndUint8Test)
@@ -334,7 +338,9 @@
     const std::vector<uint8_t> expectedOutput({ 1, 1, 1, 1,  0, 0, 0, 0,
                                                 0, 0, 0, 0,  1, 1, 1, 1 });
 
-    ArithmeticSimpleEndToEnd<armnn::DataType::QuantisedAsymm8>(defaultBackends, LayerType::Equal, expectedOutput);
+    ArithmeticSimpleEndToEnd<armnn::DataType::QuantisedAsymm8, armnn::DataType::Boolean>(defaultBackends,
+                                                                                         LayerType::Equal,
+                                                                                         expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefGreaterSimpleEndToEndUint8Test)
@@ -342,23 +348,29 @@
     const std::vector<uint8_t> expectedOutput({ 0, 0, 0, 0,  1, 1, 1, 1,
                                                 0, 0, 0, 0,  0, 0, 0, 0 });
 
-    ArithmeticSimpleEndToEnd<armnn::DataType::QuantisedAsymm8>(defaultBackends, LayerType::Greater, expectedOutput);
+    ArithmeticSimpleEndToEnd<armnn::DataType::QuantisedAsymm8, armnn::DataType::Boolean>(defaultBackends,
+                                                                                         LayerType::Greater,
+                                                                                         expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefEqualBroadcastEndToEndTest)
 {
-    const std::vector<float > expectedOutput({ 1, 0, 1, 1, 0, 0,
-                                               0, 0, 0, 0, 0, 0 });
+    const std::vector<uint8_t> expectedOutput({ 1, 0, 1, 1, 0, 0,
+                                                0, 0, 0, 0, 0, 0 });
 
-    ArithmeticBroadcastEndToEnd<armnn::DataType::Float32>(defaultBackends, LayerType::Equal, expectedOutput);
+    ArithmeticBroadcastEndToEnd<armnn::DataType::Float32, armnn::DataType::Boolean>(defaultBackends,
+                                                                                    LayerType::Equal,
+                                                                                    expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefGreaterBroadcastEndToEndTest)
 {
-    const std::vector<float> expectedOutput({ 0, 1, 0, 0, 0, 1,
-                                              1, 1, 1, 1, 1, 1 });
+    const std::vector<uint8_t> expectedOutput({ 0, 1, 0, 0, 0, 1,
+                                                1, 1, 1, 1, 1, 1 });
 
-    ArithmeticBroadcastEndToEnd<armnn::DataType::Float32>(defaultBackends, LayerType::Greater, expectedOutput);
+    ArithmeticBroadcastEndToEnd<armnn::DataType::Float32, armnn::DataType::Boolean>(defaultBackends,
+                                                                                    LayerType::Greater,
+                                                                                    expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefEqualBroadcastEndToEndUint8Test)
@@ -366,7 +378,9 @@
     const std::vector<uint8_t > expectedOutput({ 1, 0, 1, 1, 0, 0,
                                                  0, 0, 0, 0, 0, 0 });
 
-    ArithmeticBroadcastEndToEnd<armnn::DataType::QuantisedAsymm8>(defaultBackends, LayerType::Equal, expectedOutput);
+    ArithmeticBroadcastEndToEnd<armnn::DataType::QuantisedAsymm8, armnn::DataType::Boolean>(defaultBackends,
+                                                                                            LayerType::Equal,
+                                                                                            expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefGreaterBroadcastEndToEndUint8Test)
@@ -374,7 +388,9 @@
     const std::vector<uint8_t> expectedOutput({ 0, 1, 0, 0, 0, 1,
                                                 1, 1, 1, 1, 1, 1 });
 
-    ArithmeticBroadcastEndToEnd<armnn::DataType::QuantisedAsymm8>(defaultBackends, LayerType::Greater, expectedOutput);
+    ArithmeticBroadcastEndToEnd<armnn::DataType::QuantisedAsymm8, armnn::DataType::Boolean>(defaultBackends,
+                                                                                            LayerType::Greater,
+                                                                                            expectedOutput);
 }
 
 BOOST_AUTO_TEST_CASE(RefMergerEndToEndDim0Test)
diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt
index f95fda0..57e89fa 100644
--- a/src/backends/reference/workloads/CMakeLists.txt
+++ b/src/backends/reference/workloads/CMakeLists.txt
@@ -40,6 +40,8 @@
     RefBatchToSpaceNdFloat32Workload.hpp
     RefBatchToSpaceNdUint8Workload.cpp
     RefBatchToSpaceNdUint8Workload.hpp
+    RefComparisonWorkload.cpp
+    RefComparisonWorkload.hpp
     RefConstantWorkload.cpp
     RefConstantWorkload.hpp
     RefConvertFp16ToFp32Workload.cpp
diff --git a/src/backends/reference/workloads/ElementwiseFunction.cpp b/src/backends/reference/workloads/ElementwiseFunction.cpp
index cb8aa70..c8c25ef 100644
--- a/src/backends/reference/workloads/ElementwiseFunction.cpp
+++ b/src/backends/reference/workloads/ElementwiseFunction.cpp
@@ -13,24 +13,26 @@
 namespace armnn
 {
 
-template <typename Functor>
-ElementwiseFunction<Functor>::ElementwiseFunction(const TensorShape& inShape0,
-                                                  const TensorShape& inShape1,
-                                                  const TensorShape& outShape,
-                                                  const float* inData0,
-                                                  const float* inData1,
-                                                  float* outData)
+template <typename Functor, typename dataTypeInput, typename dataTypeOutput>
+ElementwiseFunction<Functor, dataTypeInput, dataTypeOutput>::ElementwiseFunction(const TensorShape& inShape0,
+                                                                                 const TensorShape& inShape1,
+                                                                                 const TensorShape& outShape,
+                                                                                 const dataTypeInput* inData0,
+                                                                                 const dataTypeInput* inData1,
+                                                                                 dataTypeOutput* outData)
 {
     BroadcastLoop(inShape0, inShape1, outShape).Unroll(Functor(), 0, inData0, inData1, outData);
 }
 
 } //namespace armnn
 
-template struct armnn::ElementwiseFunction<std::plus<float>>;
-template struct armnn::ElementwiseFunction<std::minus<float>>;
-template struct armnn::ElementwiseFunction<std::multiplies<float>>;
-template struct armnn::ElementwiseFunction<std::divides<float>>;
-template struct armnn::ElementwiseFunction<armnn::maximum<float>>;
-template struct armnn::ElementwiseFunction<armnn::minimum<float>>;
-template struct armnn::ElementwiseFunction<std::equal_to<float>>;
-template struct armnn::ElementwiseFunction<std::greater<float>>;
+template struct armnn::ElementwiseFunction<std::plus<float>, float, float>;
+template struct armnn::ElementwiseFunction<std::minus<float>, float, float>;
+template struct armnn::ElementwiseFunction<std::multiplies<float>, float, float>;
+template struct armnn::ElementwiseFunction<std::divides<float>, float, float>;
+template struct armnn::ElementwiseFunction<armnn::maximum<float>, float, float>;
+template struct armnn::ElementwiseFunction<armnn::minimum<float>, float, float>;
+template struct armnn::ElementwiseFunction<std::equal_to<float>, float ,uint8_t>;
+template struct armnn::ElementwiseFunction<std::equal_to<uint8_t>, uint8_t, uint8_t>;
+template struct armnn::ElementwiseFunction<std::greater<float>, float, uint8_t>;
+template struct armnn::ElementwiseFunction<std::greater<uint8_t>, uint8_t, uint8_t>;
diff --git a/src/backends/reference/workloads/ElementwiseFunction.hpp b/src/backends/reference/workloads/ElementwiseFunction.hpp
index 0ac1364..8099f32 100644
--- a/src/backends/reference/workloads/ElementwiseFunction.hpp
+++ b/src/backends/reference/workloads/ElementwiseFunction.hpp
@@ -10,15 +10,15 @@
 namespace armnn
 {
 
-template <typename Functor>
+template <typename Functor, typename dataTypeInput, typename dataTypeOutput>
 struct ElementwiseFunction
 {
     ElementwiseFunction(const TensorShape& inShape0,
                         const TensorShape& inShape1,
                         const TensorShape& outShape,
-                        const float* inData0,
-                        const float* inData1,
-                        float* outData);
+                        const dataTypeInput* inData0,
+                        const dataTypeInput* inData1,
+                        dataTypeOutput* outData);
 };
 
 } //namespace armnn
diff --git a/src/backends/reference/workloads/RefComparisonWorkload.cpp b/src/backends/reference/workloads/RefComparisonWorkload.cpp
new file mode 100644
index 0000000..fe517ff
--- /dev/null
+++ b/src/backends/reference/workloads/RefComparisonWorkload.cpp
@@ -0,0 +1,65 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "RefComparisonWorkload.hpp"
+#include "ElementwiseFunction.hpp"
+#include "RefWorkloadUtils.hpp"
+#include "Profiling.hpp"
+#include <vector>
+
+namespace armnn {
+
+template<typename ParentDescriptor, typename Functor>
+void RefFloat32ComparisonWorkload<ParentDescriptor, Functor>::ExecuteImpl(const char* debugString) const
+{
+    ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, debugString);
+
+    auto data = BaseFloat32ComparisonWorkload<ParentDescriptor>::GetData();
+    const TensorShape& inShape0 = GetTensorInfo(data.m_Inputs[0]).GetShape();
+    const TensorShape& inShape1 = GetTensorInfo(data.m_Inputs[1]).GetShape();
+    const TensorShape& outputShape = GetTensorInfo(data.m_Outputs[0]).GetShape();
+
+    const float* inData0 = GetInputTensorDataFloat(0, data);
+    const float* inData1 = GetInputTensorDataFloat(1, data);
+    uint8_t* outData = GetOutputTensorData<uint8_t>(0, data);
+
+    ElementwiseFunction<Functor, float, uint8_t>(inShape0,
+                                                 inShape1,
+                                                 outputShape,
+                                                 inData0,
+                                                 inData1,
+                                                 outData);
+
+}
+
+template<typename ParentDescriptor, typename Functor>
+void RefUint8ComparisonWorkload<ParentDescriptor, Functor>::ExecuteImpl(const char* debugString) const
+{
+    ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, debugString);
+
+    auto data = BaseUint8ComparisonWorkload<ParentDescriptor>::GetData();
+    const TensorShape& inputInfo0 = GetTensorInfo(data.m_Inputs[0]).GetShape();
+    const TensorShape& inputInfo1 = GetTensorInfo(data.m_Inputs[1]).GetShape();
+    const TensorShape& outputShape = GetTensorInfo(data.m_Outputs[0]).GetShape();
+
+    const uint8_t* inData0 = GetInputTensorData<uint8_t>(0, data);
+    const uint8_t* inData1 = GetInputTensorData<uint8_t>(1, data);
+    uint8_t* outData = GetOutputTensorData<uint8_t>(0, data);
+
+    ElementwiseFunction<Functor, uint8_t, uint8_t>(inputInfo0,
+                                                   inputInfo1,
+                                                   outputShape,
+                                                   inData0,
+                                                   inData1,
+                                                   outData);
+}
+
+}
+
+template class armnn::RefFloat32ComparisonWorkload<armnn::EqualQueueDescriptor, std::equal_to<float>>;
+template class armnn::RefUint8ComparisonWorkload<armnn::EqualQueueDescriptor, std::equal_to<uint8_t>>;
+
+template class armnn::RefFloat32ComparisonWorkload<armnn::GreaterQueueDescriptor, std::greater<float>>;
+template class armnn::RefUint8ComparisonWorkload<armnn::GreaterQueueDescriptor, std::greater<uint8_t>>;
diff --git a/src/backends/reference/workloads/RefComparisonWorkload.hpp b/src/backends/reference/workloads/RefComparisonWorkload.hpp
new file mode 100644
index 0000000..524d206
--- /dev/null
+++ b/src/backends/reference/workloads/RefComparisonWorkload.hpp
@@ -0,0 +1,92 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <armnn/Types.hpp>
+#include <backendsCommon/Workload.hpp>
+#include <backendsCommon/WorkloadData.hpp>
+#include "StringMapping.hpp"
+
+namespace armnn
+{
+
+template <typename Functor,
+          typename armnn::DataType DataType,
+          typename ParentDescriptor,
+          typename armnn::StringMapping::Id DebugString>
+class RefComparisonWorkload
+{
+    // Needs specialization. The default is empty on purpose.
+};
+
+template <typename ParentDescriptor, typename Functor>
+class RefFloat32ComparisonWorkload : public BaseFloat32ComparisonWorkload<ParentDescriptor>
+{
+public:
+    using BaseFloat32ComparisonWorkload<ParentDescriptor>::BaseFloat32ComparisonWorkload;
+    void ExecuteImpl(const char * debugString) const;
+};
+
+template <typename Functor, typename ParentDescriptor, typename armnn::StringMapping::Id DebugString>
+class RefComparisonWorkload<Functor, armnn::DataType::Float32, ParentDescriptor, DebugString>
+    : public RefFloat32ComparisonWorkload<ParentDescriptor, Functor>
+{
+public:
+    using RefFloat32ComparisonWorkload<ParentDescriptor, Functor>::RefFloat32ComparisonWorkload;
+
+    virtual void Execute() const override
+    {
+        using Parent = RefFloat32ComparisonWorkload<ParentDescriptor, Functor>;
+        Parent::ExecuteImpl(StringMapping::Instance().Get(DebugString));
+    }
+};
+
+template <typename ParentDescriptor, typename Functor>
+class RefUint8ComparisonWorkload : public BaseUint8ComparisonWorkload<ParentDescriptor>
+{
+public:
+    using BaseUint8ComparisonWorkload<ParentDescriptor>::BaseUint8ComparisonWorkload;
+    void ExecuteImpl(const char * debugString) const;
+};
+
+template <typename Functor, typename ParentDescriptor, typename armnn::StringMapping::Id DebugString>
+class RefComparisonWorkload<Functor, armnn::DataType::QuantisedAsymm8, ParentDescriptor, DebugString>
+    : public RefUint8ComparisonWorkload<ParentDescriptor, Functor>
+{
+public:
+    using RefUint8ComparisonWorkload<ParentDescriptor, Functor>::RefUint8ComparisonWorkload;
+
+    virtual void Execute() const override
+    {
+        using Parent = RefUint8ComparisonWorkload<ParentDescriptor, Functor>;
+        Parent::ExecuteImpl(StringMapping::Instance().Get(DebugString));
+    }
+};
+
+using RefEqualFloat32Workload =
+    RefComparisonWorkload<std::equal_to<float>,
+                          DataType::Float32,
+                          EqualQueueDescriptor,
+                          StringMapping::RefEqualWorkload_Execute>;
+
+using RefEqualUint8Workload =
+    RefComparisonWorkload<std::equal_to<uint8_t>,
+                          DataType::QuantisedAsymm8,
+                          EqualQueueDescriptor,
+                          StringMapping::RefEqualWorkload_Execute>;
+
+using RefGreaterFloat32Workload =
+    RefComparisonWorkload<std::greater<float>,
+                          DataType::Float32,
+                          GreaterQueueDescriptor,
+                          StringMapping::RefGreaterWorkload_Execute>;
+
+using RefGreaterUint8Workload =
+    RefComparisonWorkload<std::greater<uint8_t>,
+                          DataType::QuantisedAsymm8,
+                          GreaterQueueDescriptor,
+                          StringMapping::RefGreaterWorkload_Execute>;
+} // armnn
diff --git a/src/backends/reference/workloads/RefElementwiseWorkload.cpp b/src/backends/reference/workloads/RefElementwiseWorkload.cpp
index 13d6e70..c9b93c8 100644
--- a/src/backends/reference/workloads/RefElementwiseWorkload.cpp
+++ b/src/backends/reference/workloads/RefElementwiseWorkload.cpp
@@ -26,7 +26,7 @@
     const float* inData1 = GetInputTensorDataFloat(1, data);
     float* outData = GetOutputTensorDataFloat(0, data);
 
-    ElementwiseFunction<Functor>(inShape0, inShape1, outShape, inData0, inData1, outData);
+    ElementwiseFunction<Functor, float, float>(inShape0, inShape1, outShape, inData0, inData1, outData);
 }
 
 template <typename ParentDescriptor, typename Functor>
@@ -44,12 +44,12 @@
 
     std::vector<float> results(outputInfo.GetNumElements());
 
-    ElementwiseFunction<Functor>(inputInfo0.GetShape(),
-                                 inputInfo1.GetShape(),
-                                 outputInfo.GetShape(),
-                                 dequant0.data(),
-                                 dequant1.data(),
-                                 results.data());
+    ElementwiseFunction<Functor, float, float>(inputInfo0.GetShape(),
+                                               inputInfo1.GetShape(),
+                                               outputInfo.GetShape(),
+                                               dequant0.data(),
+                                               dequant1.data(),
+                                               results.data());
 
     Quantize(GetOutputTensorDataU8(0, data), results.data(), outputInfo);
 }
@@ -73,9 +73,3 @@
 
 template class armnn::BaseFloat32ElementwiseWorkload<armnn::MinimumQueueDescriptor, armnn::minimum<float>>;
 template class armnn::BaseUint8ElementwiseWorkload<armnn::MinimumQueueDescriptor, armnn::minimum<float>>;
-
-template class armnn::BaseFloat32ElementwiseWorkload<armnn::EqualQueueDescriptor, std::equal_to<float>>;
-template class armnn::BaseUint8ElementwiseWorkload<armnn::EqualQueueDescriptor, std::equal_to<float>>;
-
-template class armnn::BaseFloat32ElementwiseWorkload<armnn::GreaterQueueDescriptor, std::greater<float>>;
-template class armnn::BaseUint8ElementwiseWorkload<armnn::GreaterQueueDescriptor, std::greater<float>>;
diff --git a/src/backends/reference/workloads/RefElementwiseWorkload.hpp b/src/backends/reference/workloads/RefElementwiseWorkload.hpp
index 6dd6865..a5ff376 100644
--- a/src/backends/reference/workloads/RefElementwiseWorkload.hpp
+++ b/src/backends/reference/workloads/RefElementwiseWorkload.hpp
@@ -144,28 +144,4 @@
                           DataType::QuantisedAsymm8,
                           MinimumQueueDescriptor,
                           StringMapping::RefMinimumWorkload_Execute>;
-
-using RefEqualFloat32Workload =
-    RefElementwiseWorkload<std::equal_to<float>,
-                          DataType::Float32,
-                          EqualQueueDescriptor,
-                          StringMapping::RefEqualWorkload_Execute>;
-
-using RefEqualUint8Workload =
-    RefElementwiseWorkload<std::equal_to<float>,
-                          DataType::QuantisedAsymm8,
-                          EqualQueueDescriptor,
-                          StringMapping::RefEqualWorkload_Execute>;
-
-using RefGreaterFloat32Workload =
-    RefElementwiseWorkload<std::greater<float>,
-                          DataType::Float32,
-                          GreaterQueueDescriptor,
-                          StringMapping::RefGreaterWorkload_Execute>;
-
-using RefGreaterUint8Workload =
-    RefElementwiseWorkload<std::greater<float>,
-                          DataType::QuantisedAsymm8,
-                          GreaterQueueDescriptor,
-                          StringMapping::RefGreaterWorkload_Execute>;
 } // armnn
diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp
index 1cbceb3..d9f4dbb 100644
--- a/src/backends/reference/workloads/RefWorkloads.hpp
+++ b/src/backends/reference/workloads/RefWorkloads.hpp
@@ -60,3 +60,4 @@
 #include "RefBatchToSpaceNdFloat32Workload.hpp"
 #include "RefDebugWorkload.hpp"
 #include "RefRsqrtFloat32Workload.hpp"
+#include "RefComparisonWorkload.hpp"