COMPMID-754: Add CLPermute validation method

Change-Id: I77ed920a43738effd55b086e3138f497057a72c5
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/121618
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Tested-by: Jenkins <bsgcomp@arm.com>
diff --git a/arm_compute/runtime/CL/functions/CLPermute.h b/arm_compute/runtime/CL/functions/CLPermute.h
index ef8ba31..a415675 100644
--- a/arm_compute/runtime/CL/functions/CLPermute.h
+++ b/arm_compute/runtime/CL/functions/CLPermute.h
@@ -44,6 +44,15 @@
      * @param[in] perm   Permutation vector
      */
     void configure(const ICLTensor *input, ICLTensor *output, const PermutationVector &perm);
+    /**  Static function to check if given info will lead to a valid configuration of @ref CLPermute.
+     *
+     * @param[in] input  First tensor input info. Data types supported: U8/S8/QS8/QASYMM8/U16/S16/QS16/F16/U32/S32/F32.
+     * @param[in] output Output tensor info. Data types supported: same as @p input.
+     * @param[in] perm   Permutation vector
+     *
+     * @return a status
+     */
+    static Status validate(const ITensorInfo *input, const ITensorInfo *output, const PermutationVector &perm);
 };
 }
 #endif /*__ARM_COMPUTE_CLPERMUTE_H__ */
diff --git a/src/core/CL/kernels/CLPermuteKernel.cpp b/src/core/CL/kernels/CLPermuteKernel.cpp
index 9837543..12c2d58 100644
--- a/src/core/CL/kernels/CLPermuteKernel.cpp
+++ b/src/core/CL/kernels/CLPermuteKernel.cpp
@@ -30,6 +30,7 @@
 #include "arm_compute/core/Error.h"
 #include "arm_compute/core/Helpers.h"
 #include "arm_compute/core/Types.h"
+#include "arm_compute/core/utils/misc/ShapeCalculator.h"
 #include "support/ToolchainSupport.h"
 
 using namespace arm_compute;
@@ -54,13 +55,19 @@
                                                          DataType::U32, DataType::S32,
                                                          DataType::F16, DataType::F32);
     ARM_COMPUTE_RETURN_ERROR_ON_MSG((input->num_dimensions() < 3), "Invalid input size!");
-    ARM_COMPUTE_RETURN_ERROR_ON_MSG(
-        (perm.num_dimensions() != 3 && ((perm[0] != 2 && perm[1] != 0 && perm[2] != 1) || (perm[0] != 1 && perm[1] != 2 && perm[2] != 0))) && (perm.num_dimensions() != 4 && ((perm[0] != 2 && perm[1] != 0
-                && perm[2] != 1)
-                || (perm[0] != 1 && perm[1] != 2 && perm[2] != 0))),
-        "Only [2, 0, 1],[1, 2, 0] and [3, 2, 0, 1] permutation is supported");
+    ARM_COMPUTE_RETURN_ERROR_ON_MSG(((perm.num_dimensions() == 3 && !(perm[0] == 2 && perm[1] == 0 && perm[2] == 1) && !(perm[0] == 1 && perm[1] == 2 && perm[2] == 0)) || (perm.num_dimensions() == 4
+                                     && !(perm[0] == 3 && perm[1] == 2 && perm[2] == 0 && perm[3] == 1))),
+                                    "Only [2, 0, 1],[1, 2, 0] and [3, 2, 0, 1] permutation is supported");
 
-    ARM_COMPUTE_UNUSED(output);
+    const TensorShape output_shape = misc::shape_calculator::compute_permutation_output_shape(*input, perm);
+
+    // Validate configured output
+    if(output->total_size() != 0)
+    {
+        ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(output->tensor_shape(), output_shape);
+        ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
+        ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_FIXED_POINT(input, output);
+    }
     return Status{};
 }
 } // namespace
@@ -112,7 +119,7 @@
 
 Status CLPermuteKernel::validate(const ITensorInfo *input, const ITensorInfo *output, const PermutationVector &perm)
 {
-    ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
+    ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
     ARM_COMPUTE_RETURN_ERROR_ON(validate_arguments(input, output, perm));
 
     return Status{};
diff --git a/src/core/NEON/kernels/NEPermuteKernel.cpp b/src/core/NEON/kernels/NEPermuteKernel.cpp
index 87e5e74..ae1d48c 100644
--- a/src/core/NEON/kernels/NEPermuteKernel.cpp
+++ b/src/core/NEON/kernels/NEPermuteKernel.cpp
@@ -49,9 +49,8 @@
                                                          DataType::U16, DataType::S16, DataType::QS16,
                                                          DataType::U32, DataType::S32,
                                                          DataType::F16, DataType::F32);
-    ARM_COMPUTE_RETURN_ERROR_ON_MSG(
-        (perm.num_dimensions() != 3 && ((perm[0] != 2 && perm[1] != 0 && perm[2] != 1) || (perm[0] != 1 && perm[1] != 2 && perm[2] != 0))),
-        "Only [2, 0, 1] and [1, 2, 0] permutation is supported");
+    ARM_COMPUTE_RETURN_ERROR_ON_MSG((perm.num_dimensions() == 3 && !(perm[0] == 2 && perm[1] == 0 && perm[2] == 1) && !(perm[0] == 1 && perm[1] == 2 && perm[2] == 0)),
+                                    "Only [2, 0, 1] and [1, 2, 0] permutation is supported");
 
     const TensorShape output_shape = misc::shape_calculator::compute_permutation_output_shape(*input, perm);
 
diff --git a/src/runtime/CL/functions/CLPermute.cpp b/src/runtime/CL/functions/CLPermute.cpp
index f23e231..146856c 100644
--- a/src/runtime/CL/functions/CLPermute.cpp
+++ b/src/runtime/CL/functions/CLPermute.cpp
@@ -25,6 +25,7 @@
 
 #include "arm_compute/core/CL/ICLTensor.h"
 #include "arm_compute/core/CL/kernels/CLPermuteKernel.h"
+#include "arm_compute/core/Error.h"
 #include "support/ToolchainSupport.h"
 
 using namespace arm_compute;
@@ -34,4 +35,10 @@
     auto k = arm_compute::support::cpp14::make_unique<CLPermuteKernel>();
     k->configure(input, output, perm);
     _kernel = std::move(k);
+}
+
+Status CLPermute::validate(const ITensorInfo *input, const ITensorInfo *output, const PermutationVector &perm)
+{
+    ARM_COMPUTE_RETURN_ERROR_ON(CLPermuteKernel::validate(input, output, perm));
+    return Status{};
 }
\ No newline at end of file
diff --git a/tests/validation/CL/Permute.cpp b/tests/validation/CL/Permute.cpp
index 6c31ccc..bdd8f6e 100644
--- a/tests/validation/CL/Permute.cpp
+++ b/tests/validation/CL/Permute.cpp
@@ -50,6 +50,56 @@
 TEST_SUITE(CL)
 TEST_SUITE(Permute)
 
+// *INDENT-OFF*
+// clang-format off
+DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(
+                                                framework::dataset::make("InputInfo",{  
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // permutation not supported
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // permutation not supported
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // permutation not supported
+                                                                                        TensorInfo(TensorShape(1U, 7U), 1, DataType::U8),              // invalid input size
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // valid
+                                                                                        TensorInfo(TensorShape(27U, 13U, 37U, 2U), 1, DataType::F32),  // valid
+                                                                                        TensorInfo(TensorShape(27U, 13U, 37U, 2U), 1, DataType::F32),  // valid
+                                                                                        TensorInfo(TensorShape(128U, 64U, 21U, 2U), 1, DataType::QASYMM8), // permutation not supported
+                                                                                        TensorInfo(TensorShape(128U, 64U, 21U, 2U), 1, DataType::F32), // permutation not supported
+                                                                                        TensorInfo(TensorShape(128U, 64U, 21U, 2U), 1, DataType::F32), // permutation not supported
+                                                                                        TensorInfo(TensorShape(128U, 64U, 21U, 2U), 1, DataType::U16), // permutation not supported
+                                                                                    }),
+                                                framework::dataset::make("OutputInfo", { 
+                                                                                        TensorInfo(TensorShape(5U, 7U, 7U, 3U), 1, DataType::U16),     
+                                                                                        TensorInfo(TensorShape(5U, 5U, 7U, 3U), 1, DataType::U16),     
+                                                                                        TensorInfo(TensorShape(7U, 7U, 7U, 3U), 1, DataType::U16),
+                                                                                        TensorInfo(TensorShape(5U, 7U), 1, DataType::U8),
+                                                                                        TensorInfo(TensorShape(5U, 7U, 7U, 3U), 1, DataType::U16), 
+                                                                                        TensorInfo(TensorShape(13U, 37U, 27U, 2U), 1, DataType::F32), 
+                                                                                        TensorInfo(TensorShape(2U, 37U, 27U, 13U), 1, DataType::F32), 
+                                                                                        TensorInfo(TensorShape(128U, 64U, 21U, 2U), 1, DataType::QASYMM8),
+                                                                                        TensorInfo(TensorShape(128U, 64U, 21U, 2U), 1, DataType::F32),
+                                                                                        TensorInfo(TensorShape(21U, 64U, 2U, 128U), 1, DataType::F32), 
+                                                                                        TensorInfo(TensorShape(2U, 21U, 64U, 128U), 1, DataType::U16), 
+                                                                                    })),
+                                                framework::dataset::make("PermutationVector", { 
+                                                                                                PermutationVector(2U, 1U, 0U),
+                                                                                                PermutationVector(2U, 2U, 1U),
+                                                                                                PermutationVector(1U, 1U, 1U),
+                                                                                                PermutationVector(2U, 0U, 1U),
+                                                                                                PermutationVector(2U, 0U, 1U), 
+                                                                                                PermutationVector(1U, 2U, 0U), 
+                                                                                                PermutationVector(3U, 2U, 0U, 1U), 
+                                                                                                PermutationVector(2U, 3U, 1U, 0U),
+                                                                                                PermutationVector(1U, 1U, 1U, 1U),
+                                                                                                PermutationVector(2U, 1U, 3U, 0U),
+                                                                                                PermutationVector(3U, 2U, 1U, 0U),
+                                                                                    })),
+                                                framework::dataset::make("Expected", { false, false, false, false, true, true, true, false, false, false, false })),
+                                            input_info, output_info, perm_vect, expected)
+{
+    ARM_COMPUTE_EXPECT(bool(CLPermute::validate(&input_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false), perm_vect)) == expected, framework::LogLevel::ERRORS);
+}
+// clang-format on
+// *INDENT-ON*
+
 DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(datasets::Small4DShapes(), framework::dataset::make("DataType", { DataType::S8, DataType::U8, DataType::S16, DataType::U16, DataType::U32, DataType::S32, DataType::F16, DataType::F32 })),
                shape, data_type)
 {
diff --git a/tests/validation/NEON/Permute.cpp b/tests/validation/NEON/Permute.cpp
index 7451d9e..872a16b 100644
--- a/tests/validation/NEON/Permute.cpp
+++ b/tests/validation/NEON/Permute.cpp
@@ -50,6 +50,41 @@
 TEST_SUITE(NEON)
 TEST_SUITE(Permute)
 
+// *INDENT-OFF*
+// clang-format off
+DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(
+                                                framework::dataset::make("InputInfo",{  
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // permutation not supported
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // permutation not supported
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // permutation not supported
+                                                                                        TensorInfo(TensorShape(1U, 7U), 1, DataType::U8),              // invalid input size
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     // valid
+                                                                                        TensorInfo(TensorShape(27U, 13U, 37U, 2U), 1, DataType::F32),  // valid
+                                                                                    }),
+                                                framework::dataset::make("OutputInfo", { 
+                                                                                        TensorInfo(TensorShape(5U, 7U, 7U, 3U), 1, DataType::U16),     
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),     
+                                                                                        TensorInfo(TensorShape(7U, 7U, 5U, 3U), 1, DataType::U16),
+                                                                                        TensorInfo(TensorShape(5U, 7U), 1, DataType::U8),
+                                                                                        TensorInfo(TensorShape(5U, 7U, 7U, 3U), 1, DataType::U16), 
+                                                                                        TensorInfo(TensorShape(13U, 37U, 27U, 2U), 1, DataType::F32),  
+                                                                                    })),
+                                                framework::dataset::make("PermutationVector", { 
+                                                                                                PermutationVector(2U, 1U, 0U),
+                                                                                                PermutationVector(2U, 2U, 1U),
+                                                                                                PermutationVector(1U, 1U, 1U),
+                                                                                                PermutationVector(2U, 0U, 1U),
+                                                                                                PermutationVector(2U, 0U, 1U), 
+                                                                                                PermutationVector(1U, 2U, 0U),
+                                                                                    })),
+                                                framework::dataset::make("Expected", { false, false, false, false, true, true })),
+                                            input_info, output_info, perm_vect, expected)
+{
+    ARM_COMPUTE_EXPECT(bool(NEPermute::validate(&input_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false), perm_vect)) == expected, framework::LogLevel::ERRORS);
+}
+// clang-format on
+// *INDENT-ON*
+
 DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(datasets::Small4DShapes(), framework::dataset::make("DataType", { DataType::S8, DataType::U8, DataType::S16, DataType::U16, DataType::U32, DataType::S32, DataType::F16, DataType::F32 })),
                shape, data_type)
 {