IVGCVSW-5410 Add front-end support for CAST
IVGCVSW-5415 Add TfLiteParser support for CAST

 * Added front end support for CAST, including support in the
Reference workload, Serialization, Deserializtion, Unit tests, and
TfLiteParser.

Signed-off-by: mathad01 <matthew.haddon@arm.com>
Change-Id: Iaf670ca5912a21ed6bc84f7f83a68b42154846bb
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs
index 438ea83..a409715 100644
--- a/src/armnnSerializer/ArmnnSchema.fbs
+++ b/src/armnnSerializer/ArmnnSchema.fbs
@@ -170,7 +170,8 @@
     Fill = 57,
     Rank = 58,
     LogicalBinary = 59,
-    Reduce = 60
+    Reduce = 60,
+    Cast = 61
 }
 
 // Base layer table to be used as part of other layers
@@ -219,6 +220,10 @@
     axis:int;
 }
 
+table CastLayer {
+    base:LayerBase;
+}
+
 enum ComparisonOperation : byte {
     Equal = 0,
     Greater = 1,
@@ -964,7 +969,8 @@
     FillLayer,
     RankLayer,
     LogicalBinaryLayer,
-    ReduceLayer
+    ReduceLayer,
+    CastLayer
 }
 
 table AnyLayer {
diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h
index 2cd88e2..dfa4966 100644
--- a/src/armnnSerializer/ArmnnSchema_generated.h
+++ b/src/armnnSerializer/ArmnnSchema_generated.h
@@ -61,6 +61,9 @@
 struct ArgMinMaxDescriptor;
 struct ArgMinMaxDescriptorBuilder;
 
+struct CastLayer;
+struct CastLayerBuilder;
+
 struct ComparisonDescriptor;
 struct ComparisonDescriptorBuilder;
 
@@ -731,11 +734,12 @@
   LayerType_Rank = 58,
   LayerType_LogicalBinary = 59,
   LayerType_Reduce = 60,
+  LayerType_Cast = 61,
   LayerType_MIN = LayerType_Addition,
-  LayerType_MAX = LayerType_Reduce
+  LayerType_MAX = LayerType_Cast
 };
 
-inline const LayerType (&EnumValuesLayerType())[61] {
+inline const LayerType (&EnumValuesLayerType())[62] {
   static const LayerType values[] = {
     LayerType_Addition,
     LayerType_Input,
@@ -797,13 +801,14 @@
     LayerType_Fill,
     LayerType_Rank,
     LayerType_LogicalBinary,
-    LayerType_Reduce
+    LayerType_Reduce,
+    LayerType_Cast
   };
   return values;
 }
 
 inline const char * const *EnumNamesLayerType() {
-  static const char * const names[62] = {
+  static const char * const names[63] = {
     "Addition",
     "Input",
     "Multiplication",
@@ -865,13 +870,14 @@
     "Rank",
     "LogicalBinary",
     "Reduce",
+    "Cast",
     nullptr
   };
   return names;
 }
 
 inline const char *EnumNameLayerType(LayerType e) {
-  if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Reduce)) return "";
+  if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Cast)) return "";
   const size_t index = static_cast<size_t>(e);
   return EnumNamesLayerType()[index];
 }
@@ -1206,11 +1212,12 @@
   Layer_RankLayer = 59,
   Layer_LogicalBinaryLayer = 60,
   Layer_ReduceLayer = 61,
+  Layer_CastLayer = 62,
   Layer_MIN = Layer_NONE,
-  Layer_MAX = Layer_ReduceLayer
+  Layer_MAX = Layer_CastLayer
 };
 
-inline const Layer (&EnumValuesLayer())[62] {
+inline const Layer (&EnumValuesLayer())[63] {
   static const Layer values[] = {
     Layer_NONE,
     Layer_ActivationLayer,
@@ -1273,13 +1280,14 @@
     Layer_FillLayer,
     Layer_RankLayer,
     Layer_LogicalBinaryLayer,
-    Layer_ReduceLayer
+    Layer_ReduceLayer,
+    Layer_CastLayer
   };
   return values;
 }
 
 inline const char * const *EnumNamesLayer() {
-  static const char * const names[63] = {
+  static const char * const names[64] = {
     "NONE",
     "ActivationLayer",
     "AdditionLayer",
@@ -1342,13 +1350,14 @@
     "RankLayer",
     "LogicalBinaryLayer",
     "ReduceLayer",
+    "CastLayer",
     nullptr
   };
   return names;
 }
 
 inline const char *EnumNameLayer(Layer e) {
-  if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_ReduceLayer)) return "";
+  if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_CastLayer)) return "";
   const size_t index = static_cast<size_t>(e);
   return EnumNamesLayer()[index];
 }
@@ -1601,6 +1610,10 @@
   static const Layer enum_value = Layer_ReduceLayer;
 };
 
+template<> struct LayerTraits<armnnSerializer::CastLayer> {
+  static const Layer enum_value = Layer_CastLayer;
+};
+
 bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer type);
 bool VerifyLayerVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
 
@@ -2640,6 +2653,49 @@
   return builder_.Finish();
 }
 
+struct CastLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef CastLayerBuilder Builder;
+  enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+    VT_BASE = 4
+  };
+  const armnnSerializer::LayerBase *base() const {
+    return GetPointer<const armnnSerializer::LayerBase *>(VT_BASE);
+  }
+  bool Verify(flatbuffers::Verifier &verifier) const {
+    return VerifyTableStart(verifier) &&
+           VerifyOffset(verifier, VT_BASE) &&
+           verifier.VerifyTable(base()) &&
+           verifier.EndTable();
+  }
+};
+
+struct CastLayerBuilder {
+  typedef CastLayer Table;
+  flatbuffers::FlatBufferBuilder &fbb_;
+  flatbuffers::uoffset_t start_;
+  void add_base(flatbuffers::Offset<armnnSerializer::LayerBase> base) {
+    fbb_.AddOffset(CastLayer::VT_BASE, base);
+  }
+  explicit CastLayerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+        : fbb_(_fbb) {
+    start_ = fbb_.StartTable();
+  }
+  CastLayerBuilder &operator=(const CastLayerBuilder &);
+  flatbuffers::Offset<CastLayer> Finish() {
+    const auto end = fbb_.EndTable(start_);
+    auto o = flatbuffers::Offset<CastLayer>(end);
+    return o;
+  }
+};
+
+inline flatbuffers::Offset<CastLayer> CreateCastLayer(
+    flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<armnnSerializer::LayerBase> base = 0) {
+  CastLayerBuilder builder_(_fbb);
+  builder_.add_base(base);
+  return builder_.Finish();
+}
+
 struct ComparisonDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
   typedef ComparisonDescriptorBuilder Builder;
   enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
@@ -9502,6 +9558,9 @@
   const armnnSerializer::ReduceLayer *layer_as_ReduceLayer() const {
     return layer_type() == armnnSerializer::Layer_ReduceLayer ? static_cast<const armnnSerializer::ReduceLayer *>(layer()) : nullptr;
   }
+  const armnnSerializer::CastLayer *layer_as_CastLayer() const {
+    return layer_type() == armnnSerializer::Layer_CastLayer ? static_cast<const armnnSerializer::CastLayer *>(layer()) : nullptr;
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyField<uint8_t>(verifier, VT_LAYER_TYPE) &&
@@ -9755,6 +9814,10 @@
   return layer_as_ReduceLayer();
 }
 
+template<> inline const armnnSerializer::CastLayer *AnyLayer::layer_as<armnnSerializer::CastLayer>() const {
+  return layer_as_CastLayer();
+}
+
 struct AnyLayerBuilder {
   typedef AnyLayer Table;
   flatbuffers::FlatBufferBuilder &fbb_;
@@ -10209,6 +10272,10 @@
       auto ptr = reinterpret_cast<const armnnSerializer::ReduceLayer *>(obj);
       return verifier.VerifyTable(ptr);
     }
+    case Layer_CastLayer: {
+      auto ptr = reinterpret_cast<const armnnSerializer::CastLayer *>(obj);
+      return verifier.VerifyTable(ptr);
+    }
     default: return true;
   }
 }
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 15ae78c..b742cd8 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -14,7 +14,6 @@
 #include <fmt/format.h>
 #include <iostream>
 
-
 using namespace armnn;
 namespace fb = flatbuffers;
 namespace serializer = armnnSerializer;
@@ -293,6 +292,16 @@
     CreateAnyLayer(fbBatchNormalizationLayer.o, serializer::Layer::Layer_BatchNormalizationLayer);
 }
 
+void SerializerStrategy::SerializeCastLayer(const armnn::IConnectableLayer* layer,
+                                            const char* name)
+{
+    IgnoreUnused(name);
+
+    auto fbBaseLayer  = CreateLayerBase(layer, serializer::LayerType::LayerType_Cast);
+    auto fbCastLayer = serializer::CreateCastLayer(m_flatBufferBuilder, fbBaseLayer);
+    CreateAnyLayer(fbCastLayer.o, serializer::Layer::Layer_CastLayer);
+}
+
 void SerializerStrategy::SerializeComparisonLayer(const armnn::IConnectableLayer* layer,
                                              const armnn::ComparisonDescriptor& descriptor,
                                              const char* name)
@@ -1868,6 +1877,11 @@
                                          name);
             break;
         }
+        case armnn::LayerType::Cast :
+        {
+            SerializeCastLayer(layer, name);
+            break;
+        }
         case armnn::LayerType::Comparison :
         {
             const armnn::ComparisonDescriptor& layerDescriptor =
diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp
index 7226006..022cf64 100644
--- a/src/armnnSerializer/Serializer.hpp
+++ b/src/armnnSerializer/Serializer.hpp
@@ -126,6 +126,9 @@
                                           const std::vector<armnn::ConstTensor>& constants,
                                           const char* name = nullptr);
 
+    void SerializeCastLayer(const armnn::IConnectableLayer* layer,
+                            const char* name = nullptr);
+
     void SerializeComparisonLayer(const armnn::IConnectableLayer* layer,
                                   const armnn::ComparisonDescriptor& descriptor,
                                   const char* name = nullptr);
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index 9d44354..3d6dd58 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -200,6 +200,33 @@
     deserializedNetwork->ExecuteStrategy(verifier);
 }
 
+BOOST_AUTO_TEST_CASE(SerializeCast)
+{
+        const std::string layerName("cast");
+
+        const armnn::TensorShape shape{1, 5, 2, 3};
+
+        const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Signed32);
+        const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
+
+        armnn::INetworkPtr network = armnn::INetwork::Create();
+        armnn::IConnectableLayer* inputLayer      = network->AddInputLayer(0);
+        armnn::IConnectableLayer* castLayer       = network->AddCastLayer(layerName.c_str());
+        armnn::IConnectableLayer* outputLayer     = network->AddOutputLayer(0);
+
+        inputLayer->GetOutputSlot(0).Connect(castLayer->GetInputSlot(0));
+        castLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+        inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
+        castLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+        armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+        BOOST_CHECK(deserializedNetwork);
+
+        LayerVerifierBase verifier(layerName, {inputInfo}, {outputInfo});
+        deserializedNetwork->ExecuteStrategy(verifier);
+}
+
 BOOST_AUTO_TEST_CASE(SerializeComparison)
 {
     const std::string layerName("comparison");