IVGCVSW-3633 Refactor HalPolicy to fully support V1.2 models

 * Templated and moved V1.0 and V1.1 Convert methods to ensure they can work with later versions of models, operations and operands.
 * The V1.2 HalPolicy no longer converts V1.2 models, operations and operands to earlier versions.
 * The V1.2 HalPolicy no longer passes operations to the V1.1 or V1.0 HalPolicies for conversion.

Signed-off-by: Mike Kelly <mike.kelly@arm.com>
Change-Id: I5de59d43a3abb1f8ac0253dc637ad68318960c76
diff --git a/1.1/HalPolicy.cpp b/1.1/HalPolicy.cpp
index e75b5c2..aa650e9 100644
--- a/1.1/HalPolicy.cpp
+++ b/1.1/HalPolicy.cpp
@@ -106,61 +106,7 @@
 bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
 {
     ALOGV("hal_1_1::HalPolicy::ConvertDiv()");
-
-    LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
-    LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
-
-    if (!input0.IsValid() || !input1.IsValid())
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    // The FuseActivation parameter is always the input index 2
-    // and it should be optional
-    ActivationFn activationFunction;
-    if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
-    if (!output)
-    {
-        return Fail("%s: Could not read output 0", __func__);
-    }
-
-    const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
-    if (IsDynamicTensor(outputInfo))
-    {
-        return Fail("%s: Dynamic output tensors are not supported", __func__);
-    }
-
-    bool isSupported = false;
-    FORWARD_LAYER_SUPPORT_FUNC(__func__,
-                               IsDivisionSupported,
-                               data.m_Backends,
-                               isSupported,
-                               input0.GetTensorInfo(),
-                               input1.GetTensorInfo(),
-                               outputInfo);
-    if (!isSupported)
-    {
-        return false;
-    }
-
-    armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
-    armnn::IConnectableLayer* const endLayer   = ProcessActivation(outputInfo, activationFunction, startLayer, data);
-
-    const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
-    const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
-
-    if (endLayer)
-    {
-        BroadcastTensor(input0, input1, startLayer, *data.m_Network);
-        return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
-    }
-
-    return Fail("%s: ProcessActivation failed", __func__);
+    return ::ConvertDiv<hal_1_1::HalPolicy>(operation, model, data);
 }
 
 bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
@@ -172,75 +118,7 @@
 bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
 {
     ALOGV("hal_1_1::HalPolicy::ConvertMean()");
-
-    LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
-    if (!input.IsValid())
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
-    if (!output)
-    {
-        return Fail("%s: Could not read output 0", __func__);
-    }
-
-    const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
-    if (IsDynamicTensor(outputInfo))
-    {
-        return Fail("%s: Dynamic output tensors are not supported", __func__);
-    }
-
-    const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
-    if (!axisOperand)
-    {
-        return Fail("%s: Could not read input 1", __func__);
-    }
-
-    std::vector<int32_t> axis;
-    if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data))
-    {
-        return Fail("%s: Input 1 has invalid values", __func__);
-    }
-
-    const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
-
-    // Convert the axis to unsigned int and remove duplicates.
-    unsigned int rank = inputInfo.GetNumDimensions();
-    std::set<unsigned int> uniqueAxis;
-    std::transform(axis.begin(), axis.end(),
-                   std::inserter(uniqueAxis, uniqueAxis.begin()),
-                   [rank](int i) -> unsigned int { return (i + rank) % rank; });
-
-    // Get the "keep dims" flag.
-    int32_t keepDims = 0;
-    if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 2, keepDims, model, data))
-    {
-        return Fail("%s: Could not read input 2", __func__);
-    }
-
-    armnn::MeanDescriptor descriptor;
-    descriptor.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
-    descriptor.m_KeepDims = keepDims > 0;
-
-    bool isSupported = false;
-    FORWARD_LAYER_SUPPORT_FUNC(__func__,
-                               IsMeanSupported,
-                               data.m_Backends,
-                               isSupported,
-                               inputInfo,
-                               outputInfo,
-                               descriptor);
-    if (!isSupported)
-    {
-        return false;
-    }
-
-    armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
-    assert(layer != nullptr);
-    input.Connect(layer->GetInputSlot(0));
-
-    return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
+    return ::ConvertMean<hal_1_1::HalPolicy>(operation, model, data);
 }
 
 bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
@@ -258,261 +136,19 @@
 bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
 {
     ALOGV("hal_1_1::HalPolicy::ConvertSqueeze()");
-
-    LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
-    if (!input.IsValid())
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    const armnn::TensorInfo& inputInfo  = input.GetTensorInfo();
-    unsigned int rank = inputInfo.GetNumDimensions();
-    if (rank > 4)
-    {
-        Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
-    }
-
-    const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
-    if (!output)
-    {
-        return Fail("%s: Could not read output 0", __func__);
-    }
-
-    if (IsDynamicTensor(GetTensorInfoForOperand(*output)))
-    {
-        return Fail("%s: Dynamic output tensors are not supported", __func__);
-    }
-
-    // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
-    // if the operand index is out of bounds.
-    const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
-
-    const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
-
-    std::vector<int32_t> axis;
-    if (!axisOperand)
-    {
-        axis.assign(dimensionSequence,
-                    dimensionSequence + rank);
-    }
-    else
-    {
-        GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data);
-    }
-
-
-    std::vector<uint32_t> outputDims;
-    for (unsigned int i = 0; i < rank; i++)
-    {
-        bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
-        auto currentDimension = inputInfo.GetShape()[i];
-        if (skipSqueeze || currentDimension != 1)
-        {
-            outputDims.push_back(currentDimension);
-        }
-    }
-
-    armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
-
-    armnn::TensorInfo outputInfo = inputInfo;
-    outputInfo.SetShape(outShape);
-
-    armnn::ReshapeDescriptor reshapeDesc;
-    reshapeDesc.m_TargetShape = outputInfo.GetShape();
-
-    bool isSupported = false;
-    FORWARD_LAYER_SUPPORT_FUNC(__func__,
-                               IsReshapeSupported,
-                               data.m_Backends,
-                               isSupported,
-                               inputInfo,
-                               reshapeDesc);
-    if (!isSupported)
-    {
-        return false;
-    }
-
-    armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
-    assert(layer != nullptr);
-    input.Connect(layer->GetInputSlot(0));
-
-    return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
+    return ::ConvertSqueeze<hal_1_1::HalPolicy>(operation, model, data);
 }
 
 bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
 {
     ALOGV("hal_1_1::HalPolicy::ConvertStridedSlice()");
-
-    LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
-    if (!input.IsValid())
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
-    unsigned int rank = inputInfo.GetNumDimensions();
-    if (rank > 4)
-    {
-        Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
-    }
-
-    const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
-    if (!output)
-    {
-        return Fail("%s: Could not read output 0", __func__);
-    }
-
-    const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
-    if (IsDynamicTensor(outputInfo))
-    {
-        return Fail("%s: Dynamic output tensors are not supported", __func__);
-    }
-
-    const Operand* beginOperand   = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
-    const Operand* endOperand     = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
-    const Operand* stridesOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 3, model);
-
-    std::vector<int32_t> beginValues;
-    std::vector<int32_t> endValues;
-    std::vector<int32_t> stridesValues;
-
-    // The length of the beginOperand, endOperand and stridesOperand must be of a rank(input)
-    auto ValidateInputOperands = [&] (const Operand& operand, std::vector<int32_t>& operandValues)
-    {
-        if (!GetTensorInt32Values<hal_1_1::HalPolicy>(operand, operandValues, model, data))
-        {
-            return false;
-        }
-
-        if (operandValues.size() != rank)
-        {
-            return false;
-        }
-
-        return true;
-    };
-
-    if (!ValidateInputOperands(*beginOperand, beginValues)
-        || !ValidateInputOperands(*endOperand, endValues)
-        || !ValidateInputOperands(*stridesOperand, stridesValues))
-    {
-        return Fail("%s: Operation has invalid input operand", __func__);
-    }
-
-    // Stride cannot have value '0'
-    if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
-    {
-        return Fail("%s: Stride must be non-zero value.", __func__);
-    }
-
-    armnn::StridedSliceDescriptor descriptor;
-    descriptor.m_Begin.assign(beginValues.cbegin(), beginValues.cend());
-    descriptor.m_End.assign(endValues.cbegin(), endValues.cend());
-    descriptor.m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
-    descriptor.m_DataLayout = armnn::DataLayout::NHWC;
-
-    // Get the "begin_mask", "end_mask", and "shrink_axis_mask" flags
-    if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 4, descriptor.m_BeginMask, model, data) ||
-        !GetInputInt32<hal_1_1::HalPolicy>(operation, 5, descriptor.m_EndMask, model, data) ||
-        !GetInputInt32<hal_1_1::HalPolicy>(operation, 6, descriptor.m_ShrinkAxisMask, model, data))
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    bool isSupported = false;
-    FORWARD_LAYER_SUPPORT_FUNC(__func__,
-                               IsStridedSliceSupported,
-                               data.m_Backends,
-                               isSupported,
-                               inputInfo,
-                               outputInfo,
-                               descriptor);
-    if (!isSupported)
-    {
-        return false;
-    }
-
-    armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor);
-    assert(layer != nullptr);
-    input.Connect(layer->GetInputSlot(0));
-
-    return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
+    return ::ConvertStridedSlice<hal_1_1::HalPolicy>(operation, model, data);
 }
 
 bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
 {
     ALOGV("hal_1_1::HalPolicy::ConvertTranspose()");
-
-    LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
-    if (!input.IsValid())
-    {
-        return Fail("%s: Operation has invalid inputs", __func__);
-    }
-
-    const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
-    unsigned int rank = inputInfo.GetNumDimensions();
-    if (rank > 4)
-    {
-        Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
-    }
-
-    // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
-    // if the operand index is out of bounds.
-    const Operand* permOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
-
-    std::vector<int32_t> perm(rank);
-    if (!permOperand)
-    {
-        // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
-        for (unsigned int i = rank; i > 0; i--)
-        {
-            perm[rank - i] = boost::numeric_cast<int> (i - 1);
-        }
-    }
-    else
-    {
-        GetTensorInt32Values<hal_1_1::HalPolicy>(*permOperand, perm, model, data);
-    }
-
-    std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
-
-    auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
-    if (!permutationVector.IsEqual(NHWCToArmNN)
-        && !permutationVector.IsEqual(ArmNNToNHWC)
-        && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
-    {
-       return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
-    }
-
-    armnn::PermuteDescriptor permuteDesc;
-    permuteDesc.m_DimMappings = permutationVector;
-
-    const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
-    if (!output)
-    {
-        return Fail("%s: Could not read output 0", __func__);
-    }
-
-    const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
-
-    bool isSupported = false;
-    FORWARD_LAYER_SUPPORT_FUNC(__func__,
-                               IsPermuteSupported,
-                               data.m_Backends,
-                               isSupported,
-                               inputInfo,
-                               outputInfo,
-                               permuteDesc);
-    if (!isSupported)
-    {
-        return false;
-    }
-
-    armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
-    assert(layer != nullptr);
-    input.Connect(layer->GetInputSlot(0));
-
-    return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
+    return ::ConvertTranspose<hal_1_1::HalPolicy>(operation, model, data);
 }
 
 bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)