IVGCVSW-6457 Add FLOOR_DIV Support to the TfLiteDelegate

Change-Id: Ia4bf42b1f3f86b947825dff8e538d2d4343effab
Signed-off-by: Jim Flynn <jim.flynn@arm.com>
diff --git a/delegate/src/ElementwiseBinary.hpp b/delegate/src/ElementwiseBinary.hpp
index 58d7aca..0534c07 100644
--- a/delegate/src/ElementwiseBinary.hpp
+++ b/delegate/src/ElementwiseBinary.hpp
@@ -6,6 +6,8 @@
 #pragma once
 
 #include "DelegateUtils.hpp"
+#include "MultiLayerFacade.hpp"
+#include "SharedFunctions.hpp"
 
 #include <tensorflow/lite/builtin_ops.h>
 #include <tensorflow/lite/c/builtin_op_data.h>
@@ -39,6 +41,7 @@
     return isSupported ? kTfLiteOk : kTfLiteError;
 }
 
+
 TfLiteStatus ValidateDivOperator(DelegateData& delegateData,
                                  TfLiteContext* tfLiteContext,
                                  const armnn::TensorInfo& inputInfo1,
@@ -62,6 +65,35 @@
     return isSupported ? kTfLiteOk : kTfLiteError;
 }
 
+TfLiteStatus ValidateFloorDivOperator(DelegateData& delegateData,
+                                      TfLiteContext* tfLiteContext,
+                                      const armnn::TensorInfo& inputInfo1,
+                                      const armnn::TensorInfo& inputInfo2,
+                                      const armnn::TensorInfo& outputInfo)
+{
+    // need first to validate that the div operator is supported
+    // then that the floor operator is supported
+    TfLiteStatus status = ValidateDivOperator(delegateData, tfLiteContext, inputInfo1, inputInfo2, outputInfo);
+    if (status != kTfLiteOk)
+    {
+        return status;
+    }
+    // if the inputs and output of the div are all Signed32 we don't need to add the floor operator afterward.
+    if (AreAllSigned32(inputInfo1, inputInfo2, outputInfo))
+    {
+        return status;
+    }
+    // in case broadcasting is being done from one of the inputs to the div
+    // choose the full sized input tensor to pass to the floor validation routine
+    armnn::TensorInfo floorInputInfo = inputInfo1;
+    if (inputInfo1.GetNumDimensions() < inputInfo2.GetNumDimensions())
+    {
+        floorInputInfo = inputInfo2;
+    }
+    status = ValidateFloorOperator(delegateData, tfLiteContext, floorInputInfo, outputInfo);
+    return status;
+}
+
 TfLiteStatus ValidateMaximumOperator(DelegateData& delegateData,
                                      TfLiteContext* tfLiteContext,
                                      const armnn::TensorInfo& inputInfo1,
@@ -154,6 +186,23 @@
     return isSupported ? kTfLiteOk : kTfLiteError;
 }
 
+std::pair<armnn::IConnectableLayer*, armnn::IConnectableLayer*> AddFloorDivLayer(
+    DelegateData& delegateData,
+    const armnn::TensorInfo& outputTensorInfo)
+{
+    armnn::IConnectableLayer* divisionLayer = delegateData.m_Network->AddDivisionLayer();
+    // if the output of the div is Signed32 the Floor layer is not required
+    if (armnn::DataType::Signed32 == outputTensorInfo.GetDataType())
+    {
+        return std::make_pair(divisionLayer, divisionLayer);
+    }
+    armnn::IOutputSlot& outputSlot = divisionLayer->GetOutputSlot(0);
+    outputSlot.SetTensorInfo(outputTensorInfo);
+    armnn::IConnectableLayer* floorLayer = delegateData.m_Network->AddFloorLayer();
+    outputSlot.Connect(floorLayer->GetInputSlot(0));
+    return std::make_pair(divisionLayer, floorLayer);
+}
+
 TfLiteStatus VisitElementwiseBinaryOperator(DelegateData& delegateData,
                                             TfLiteContext* tfLiteContext,
                                             TfLiteNode* tfLiteNode,
@@ -215,6 +264,12 @@
                                            inputTensorInfo0,
                                            inputTensorInfo1,
                                            outputTensorInfo);
+            case kTfLiteBuiltinFloorDiv:
+                return ValidateFloorDivOperator(delegateData,
+                                                tfLiteContext,
+                                                inputTensorInfo0,
+                                                inputTensorInfo1,
+                                                outputTensorInfo);
             case kTfLiteBuiltinMaximum:
                 return ValidateMaximumOperator(delegateData,
                                                tfLiteContext,
@@ -245,7 +300,7 @@
     }
 
     armnn::IConnectableLayer* elementwiseBinaryLayer = nullptr;
-
+    MultiLayerFacade multiLayer;
     switch(elementwiseBinaryOperatorCode)
     {
         case kTfLiteBuiltinAdd:
@@ -254,6 +309,13 @@
         case kTfLiteBuiltinDiv:
             elementwiseBinaryLayer = delegateData.m_Network->AddDivisionLayer();
             break;
+        case kTfLiteBuiltinFloorDiv:
+            {
+                auto layers = AddFloorDivLayer(delegateData, outputTensorInfo);
+                multiLayer.AssignValues(layers.first, layers.second);
+                elementwiseBinaryLayer = &multiLayer;
+            }
+            break;
         case kTfLiteBuiltinMaximum:
             elementwiseBinaryLayer = delegateData.m_Network->AddMaximumLayer();
             break;