COMPMID-408 Create OpenCL complex math functions for 8 bit fixed point arithmetic.

Logarithm, inverse square root, exponential and multiplication for
8 bit fixed point arithmetic in OPenCL.

Change-Id: Ib976da7057242967c940df28ceebf39bc3ea3811
Reviewed-on: http://mpd-gerrit.cambridge.arm.com/78273
Reviewed-by: Moritz Pflanzer <moritz.pflanzer@arm.com>
Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
diff --git a/arm_compute/core/CL/CLKernelLibrary.h b/arm_compute/core/CL/CLKernelLibrary.h
index c29610c..38cfad6 100644
--- a/arm_compute/core/CL/CLKernelLibrary.h
+++ b/arm_compute/core/CL/CLKernelLibrary.h
@@ -174,6 +174,17 @@
     {
         _kernel_path = kernel_path;
     };
+    /** Gets the path that the kernels reside in.
+     */
+    std::string get_kernel_path()
+    {
+        return _kernel_path;
+    };
+    /** Gets the source of the selected program
+      *
+      * @param[in] program_name Program name.
+     */
+    std::string get_program_source(const std::string &program_name);
     /** Sets the CL context used to create programs.
      *
      * @note Setting the context also resets the device to the
diff --git a/src/core/CL/CLKernelLibrary.cpp b/src/core/CL/CLKernelLibrary.cpp
index 6cf5ce2..4a92bac 100644
--- a/src/core/CL/CLKernelLibrary.cpp
+++ b/src/core/CL/CLKernelLibrary.cpp
@@ -486,7 +486,7 @@
     {
         "warp_perspective.cl",
 #include "./cl_kernels/warp_perspective.clembed"
-    }
+    },
 #endif
 };
 
@@ -602,3 +602,15 @@
 
     return concat_set;
 }
+
+std::string CLKernelLibrary::get_program_source(const std::string &program_name)
+{
+    const auto program_source_it = _program_source_map.find(program_name);
+
+    if(program_source_it == _program_source_map.end())
+    {
+        ARM_COMPUTE_ERROR("Embedded program for %s does not exist.", program_name.c_str());
+    }
+
+    return program_source_it->second;
+}
diff --git a/src/core/CL/cl_kernels/fixed_point.h b/src/core/CL/cl_kernels/fixed_point.h
index c0855db..32e49c2 100644
--- a/src/core/CL/cl_kernels/fixed_point.h
+++ b/src/core/CL/cl_kernels/fixed_point.h
@@ -60,6 +60,13 @@
 #define qs16x8_TYPE short8
 #define qs16x16_TYPE short16
 
+/* All internal constants are represented in the maximum supported fixed point format (QS16),
+ * thus we define an additional shift parameter required to convert the constant
+ * from the maximum supported format to the require one.
+ */
+#define qs8_SHIFT 8
+#define qs16_SHIFT 0
+
 #undef VEC_DATA_TYPE_STR
 #undef VEC_DATA_TYPE
 #undef CONVERT_STR
@@ -80,12 +87,12 @@
 #define CONVERT_SAT_STR(x, type) CONVERT_SAT_STR2(x, type, type##_TYPE)
 #define CONVERT_SAT(x, type) CONVERT_SAT_STR(x, type)
 
-/* Computes max of fixed point types.
- *
- * @param[in] type the actual data type.
- *
- * @return The result of the fixed point maximum.
- */
+/** Computes max of fixed point types.
+  *
+  * @param[in] type the actual data type.
+  *
+  * @return The result of the fixed point maximum.
+  */
 #define MAXQ_IMPL(type)                          \
     inline type max_##type(type VopA, type VopB) \
     {                                            \
@@ -101,12 +108,12 @@
 #define MAX_OP_EXPAND_STR(a, b, type, size) max_##type##x##size((a), (b))
 #define MAX_OP_EXPAND(a, b, type, size) MAX_OP_EXPAND_STR(a, b, type, size)
 
-/* Computes saturated addition of fixed point types.
- *
- * @param[in] type the actual data type.
- *
- * @return The result of the fixed point addition. The result is saturated in case of overflow
- */
+/** Computes saturated addition of fixed point types.
+  *
+  * @param[in] type the actual data type.
+  *
+  * @return The result of the fixed point addition. The result is saturated in case of overflow
+  */
 #define ADDQ_SAT_IMPL(type)                          \
     inline type add_sat_##type(type VopA, type VopB) \
     {                                                \
@@ -122,12 +129,12 @@
 #define ADD_SAT_OP_EXPAND_STR(a, b, type, size) add_sat_##type##x##size((a), (b))
 #define ADD_SAT_OP_EXPAND(a, b, type, size) ADD_SAT_OP_EXPAND_STR(a, b, type, size)
 
-/* Computes saturated subtraction of fixed point types.
- *
- * @param[in] type the actual data type.
- *
- * @return The result of the fixed point subtraction. The result is saturated in case of overflow
- */
+/** Computes saturated subtraction of fixed point types.
+  *
+  * @param[in] type the actual data type.
+  *
+  * @return The result of the fixed point subtraction. The result is saturated in case of overflow
+  */
 #define SUBQ_SAT_IMPL(type)                          \
     inline type sub_sat_##type(type VopA, type VopB) \
     {                                                \
@@ -143,13 +150,13 @@
 #define SUB_SAT_OP_EXPAND_STR(a, b, type, size) sub_sat_##type##x##size((a), (b))
 #define SUB_SAT_OP_EXPAND(a, b, type, size) SUB_SAT_OP_EXPAND_STR(a, b, type, size)
 
-/* Saturate multiply of two fixed point numbers
- *
- * @param[in] type  the actual data type.
- * @param[in] itype the intermediate data type.
- *
- * @return The result of the fixed point multiplication. The result is saturated in case of overflow
- */
+/** Saturate multiply of two fixed point numbers
+  *
+  * @param[in] type  the actual data type.
+  * @param[in] itype the intermediate data type.
+  *
+  * @return The result of the fixed point multiplication. The result is saturated in case of overflow
+  */
 #define MULQ_SAT_IMPL(type, itype)                                                            \
     inline type mul_sat_##type(type VopA, type VopB, int fixed_point_position)                \
     {                                                                                         \
@@ -163,13 +170,13 @@
 #define MUL_SAT_OP_EXPAND_STR(a, b, type, size, position) mul_sat_##type##x##size((a), (b), (position))
 #define MUL_SAT_OP_EXPAND(a, b, type, size, position) MUL_SAT_OP_EXPAND_STR(a, b, type, size, position)
 
-/* Saturate multiply-accumulate
- *
- * @param[in] type  the actual data type.
- * @param[in] itype the intermediate data type.
- *
- * @return The result of the fixed point multiply-accumulate. The result is saturated in case of overflow
- */
+/** Saturate multiply-accumulate
+  *
+  * @param[in] type  the actual data type.
+  * @param[in] itype the intermediate data type.
+  *
+  * @return The result of the fixed point multiply-accumulate. The result is saturated in case of overflow
+  */
 #define MLAQ_SAT_IMPL(type, itype)                                                                                 \
     type mla_sat_##type(type VopA, type VopB, type VopC, int fixed_point_position)                                 \
     {                                                                                                              \
@@ -183,13 +190,13 @@
 #define MLA_SAT_OP_EXPAND_STR(a, b, c, type, size, position) mla_sat_##type##x##size((a), (b), (c), (position))
 #define MLA_SAT_OP_EXPAND(a, b, c, type, size, position) MLA_SAT_OP_EXPAND_STR(a, b, c, type, size, position)
 
-/* Saturate multiply-accumulate long
- *
- * @param[in] type  the actual data type.
- * @param[in] itype the intermediate data type.
- *
- * @return The result of the fixed point multiply-accumulate long. The result is saturated in case of overflow
- */
+/** Saturate multiply-accumulate long
+  *
+  * @param[in] type  the actual data type.
+  * @param[in] itype the intermediate data type.
+  *
+  * @return The result of the fixed point multiply-accumulate long. The result is saturated in case of overflow
+  */
 #define MLALQ_SAT_IMPL(type, itype)                                                                                \
     itype mlal_sat_##type(itype VopA, type VopB, type VopC, int fixed_point_position)                              \
     {                                                                                                              \
@@ -225,44 +232,99 @@
 #define DIV_SAT_OP_EXPAND_STR(a, b, type, size, position) div_sat_##type##x##size((a), (b), (position))
 #define DIV_SAT_OP_EXPAND(a, b, type, size, position) DIV_SAT_OP_EXPAND_STR(a, b, type, size, position)
 
-/** Saturate exponential fixed point 8 bit (16 elements)
+/** Saturate exponential of a fixed point vector
   *
-  * @param[in] a                    8 bit fixed point input vector
-  * @param[in] fixed_point_position Fixed point position that expresses the number of bits for the fractional part of the number
- *
- * @return The result of the 8 bit fixed point exponential. The result is saturated in case of overflow
- */
-qs8x16 inline exp_qs8x16(qs8x16 a, int fixed_point_position)
-{
-    // Constants (literal constants are calculated by converting the respective float to the fixed point with the highest supported fixed point position)
-    char16 const_one = (char16)(1 << (fixed_point_position));
-    char16 ln2       = (char16)(((0x58 >> (6 - fixed_point_position)) + 1) >> 1);                 // 0.693147
-    char16 inv_ln2   = ((char16)(((0x38 >> (6 - (fixed_point_position))) + 1) >> 1)) | const_one; // 1.442695
-    char16 A         = (char16)(((0x7F >> (6 - (fixed_point_position))) + 1) >> 1);               // 0.9978546
-    char16 B         = (char16)(((0x3F >> (6 - (fixed_point_position))) + 1) >> 1);               // 0.4994721
-    char16 C         = (char16)(((0x16 >> (6 - (fixed_point_position))) + 1) >> 1);               // 0.1763723
-    char16 D         = (char16)(((0x05 >> (6 - (fixed_point_position))) + 1) >> 1);               // 0.0435108
+  * @param[in] stype the actual scalar data type.
+  * @param[in] type  the actual data type.
+  * @param[in] size  the number of the calculated elements.
+  *
+  * @return The result of the fixed point exponential. The result is saturated in case of overflow
+  */
+#define EXPQ_IMPL(stype, type, size)                                                                                     \
+    inline type exp_sat_##type(type VopA, int fixed_point_position)                                                      \
+    {                                                                                                                    \
+        type const_one = (type)(1 << (fixed_point_position));                                                            \
+        type ln2       = (type)((((0x58B9 >> (14 - fixed_point_position))) + 1) >> 1);                                   \
+        type inv_ln2   = (type)((((0x38AA >> (14 - fixed_point_position)) + 1) >> 1)) | const_one;                       \
+        type A         = (type)(((0x7FBA >> (14 - fixed_point_position)) + 1) >> 1);                                     \
+        type B         = (type)(((0x3FE9 >> (14 - fixed_point_position)) + 1) >> 1);                                     \
+        type C         = (type)(((0x1693 >> (14 - fixed_point_position)) + 1) >> 1);                                     \
+        type D         = (type)(((0x0592 >> (14 - fixed_point_position)) + 1) >> 1);                                     \
+        type m         = MUL_SAT_OP_EXPAND(VopA, inv_ln2, stype, size, fixed_point_position);                            \
+        type dec_m     = m >> (type)fixed_point_position;                                                                \
+        type alpha     = MUL_SAT_OP_EXPAND(dec_m << (type)fixed_point_position, ln2, stype, size, fixed_point_position); \
+        alpha          = CONVERT(abs_diff(VopA, alpha), type);                                                           \
+        type sum       = add_sat(MUL_SAT_OP_EXPAND(alpha, D, stype, size, fixed_point_position), C);                     \
+        sum            = add_sat(MUL_SAT_OP_EXPAND(alpha, sum, stype, size, fixed_point_position), B);                   \
+        sum            = add_sat(MUL_SAT_OP_EXPAND(alpha, sum, stype, size, fixed_point_position), A);                   \
+        sum            = add_sat(MUL_SAT_OP_EXPAND(alpha, sum, stype, size, fixed_point_position), const_one);           \
+        return select(select(sum << dec_m, sum >> -dec_m, dec_m < (type)0), (type)stype##_MAX, clz(sum) <= dec_m);       \
+    }
 
-    // Perform range reduction [-log(2),log(2)]
-    char16 m = mul_sat_qs8x16(a, inv_ln2, fixed_point_position);
+EXPQ_IMPL(qs8, qs8x16, 16)
 
-    // get decimal part of m
-    char16 dec_m = m >> (char16)fixed_point_position;
-
-    char16 alpha = mul_sat_qs8x16(dec_m << (char16)fixed_point_position, ln2, fixed_point_position);
-    alpha        = convert_char16(abs_diff(a, alpha));
-
-    // Polynomial expansion
-    char16 sum = add_sat_qs8x16(mul_sat_qs8x16(alpha, D, fixed_point_position), C);
-    sum        = add_sat_qs8x16(mul_sat_qs8x16(alpha, sum, fixed_point_position), B);
-    sum        = add_sat_qs8x16(mul_sat_qs8x16(alpha, sum, fixed_point_position), A);
-    sum        = add_sat_qs8x16(mul_sat_qs8x16(alpha, sum, fixed_point_position), const_one);
-
-    // Reconstruct and saturate result
-    return select(select(sum << dec_m, sum >> -dec_m, dec_m < (char16)0), (char16)0x7F, clz(sum) <= dec_m);
-}
-
-#define EXP_OP_EXPAND_STR(a, type, size, position) exp_##type##x##size((a), (position))
+#define EXP_OP_EXPAND_STR(a, type, size, position) exp_sat_##type##x##size((a), (position))
 #define EXP_OP_EXPAND(a, type, size, position) EXP_OP_EXPAND_STR(a, type, size, position)
 
+/** Saturate logarithm of a fixed point vector
+  *
+  * @param[in] stype the actual scalar data type.
+  * @param[in] type  the actual data type.
+  * @param[in] size  the number of the calculated elements.
+  *
+  * @return The result of the fixed point logarithm. The result is saturated in case of overflow
+  */
+#define LOGQ_IMPL(stype, type, size)                                                                                                       \
+    inline type log_sat_##type(type VopA, int fixed_point_position)                                                                        \
+    {                                                                                                                                      \
+        type const_one = (type)(1 << (fixed_point_position));                                                                              \
+        type ln2       = (type)(0x58B9 >> (15 - fixed_point_position));                                                                    \
+        type A         = (type)(0x5C0F >> (14 - fixed_point_position));                                                                    \
+        type B         = -(type)(0x56AE >> (15 - fixed_point_position));                                                                   \
+        type C         = (type)(0x2933 >> (15 - fixed_point_position));                                                                    \
+        type D         = -(type)(0x0AA7 >> (15 - fixed_point_position));                                                                   \
+        type inter_a   = select(VopA, DIV_SAT_OP_EXPAND(const_one, VopA, stype, size, fixed_point_position), VopA < const_one);            \
+        type shift_val = (type)(15 - stype##_SHIFT) - clz(inter_a >> (type)fixed_point_position);                                          \
+        inter_a        = inter_a >> shift_val;                                                                                             \
+        inter_a        = sub_sat(inter_a, const_one);                                                                                      \
+        type sum       = add_sat(MUL_SAT_OP_EXPAND(inter_a, D, stype, size, fixed_point_position), C);                                     \
+        sum            = add_sat(MUL_SAT_OP_EXPAND(inter_a, sum, stype, size, fixed_point_position), B);                                   \
+        sum            = add_sat(MUL_SAT_OP_EXPAND(inter_a, sum, stype, size, fixed_point_position), A);                                   \
+        sum            = MUL_SAT_OP_EXPAND(inter_a, sum, stype, size, fixed_point_position);                                               \
+        sum            = MUL_SAT_OP_EXPAND(add_sat(sum, shift_val << (type)fixed_point_position), ln2, stype, size, fixed_point_position); \
+        return select(select(sum, -sum, VopA < const_one), (type)0, VopA < (type)0);                                                       \
+    }
+
+LOGQ_IMPL(qs8, qs8x16, 16)
+
+#define LOG_OP_EXPAND_STR(a, type, size, position) log_sat_##type##x##size((a), (position))
+#define LOG_OP_EXPAND(a, type, size, position) LOG_OP_EXPAND_STR(a, type, size, position)
+
+/** Saturate inverse square root of a fixed point vector
+  *
+  * @param[in] stype the actual scalar data type.
+  * @param[in] type  the actual data type.
+  * @param[in] size  the number of the calculated elements.
+  *
+  * @return The result of the fixed point inverse square root. The result is saturated in case of overflow
+  */
+#define INVSQRTQ_IMPL(stype, type, size)                                                                                                                                                                                               \
+    inline type invsqrt_sat_##type(type VopA, int fixed_point_position)                                                                                                                                                                \
+    {                                                                                                                                                                                                                                  \
+        type const_three = (type)(3 << (fixed_point_position));                                                                                                                                                                        \
+        type shift_value = (type)(16 - stype##_SHIFT) - (clz(VopA) + (type)fixed_point_position);                                                                                                                                      \
+        type temp        = select(VopA >> shift_value, VopA << (-shift_value), shift_value < (type)0);                                                                                                                                 \
+        type x           = temp;                                                                                                                                                                                                       \
+        x                = MUL_SAT_OP_EXPAND(x, sub_sat(const_three, MUL_SAT_OP_EXPAND(MUL_SAT_OP_EXPAND(x, x, stype, size, fixed_point_position), temp, stype, size, fixed_point_position)), stype, size, fixed_point_position) >> 1; \
+        x                = MUL_SAT_OP_EXPAND(x, sub_sat(const_three, MUL_SAT_OP_EXPAND(MUL_SAT_OP_EXPAND(x, x, stype, size, fixed_point_position), temp, stype, size, fixed_point_position)), stype, size, fixed_point_position) >> 1; \
+        x                = MUL_SAT_OP_EXPAND(x, sub_sat(const_three, MUL_SAT_OP_EXPAND(MUL_SAT_OP_EXPAND(x, x, stype, size, fixed_point_position), temp, stype, size, fixed_point_position)), stype, size, fixed_point_position) >> 1; \
+        type res         = select(x >> (shift_value >> 1), x << ((-shift_value) >> 1), shift_value < (type)0);                                                                                                                         \
+        return select(res, stype##_MAX, res < (type)0);                                                                                                                                                                                \
+    }
+
+INVSQRTQ_IMPL(qs8, qs8x16, 16)
+
+#define INVSQRT_OP_EXPAND_STR(a, type, size, position) invsqrt_sat_##type##x##size((a), (position))
+#define INVSQRT_OP_EXPAND(a, type, size, position) INVSQRT_OP_EXPAND_STR(a, type, size, position)
+
 #endif // ARM_COMPUTE_FIXED_POINT_H
diff --git a/tests/dataset/ShapeDatasets.h b/tests/dataset/ShapeDatasets.h
index ecb478d..1e9e5f1 100644
--- a/tests/dataset/ShapeDatasets.h
+++ b/tests/dataset/ShapeDatasets.h
@@ -97,7 +97,7 @@
 {
 public:
     Small1DShape()
-        : ShapeDataset(TensorShape(128U))
+        : ShapeDataset(TensorShape(256U))
     {
     }
 };
diff --git a/tests/validation/CL/FixedPoint/FixedPoint_QS8.cpp b/tests/validation/CL/FixedPoint/FixedPoint_QS8.cpp
new file mode 100644
index 0000000..fabd9ad
--- /dev/null
+++ b/tests/validation/CL/FixedPoint/FixedPoint_QS8.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "CL/CLAccessor.h"
+#include "Globals.h"
+#include "TensorLibrary.h"
+#include "TypePrinter.h"
+#include "Utils.h"
+#include "validation/Datasets.h"
+#include "validation/Reference.h"
+#include "validation/Validation.h"
+
+#include "arm_compute/core/CL/CLKernelLibrary.h"
+#include "arm_compute/core/CL/ICLKernel.h"
+#include "arm_compute/core/CL/OpenCL.h"
+#include "arm_compute/core/Helpers.h"
+#include "arm_compute/core/Types.h"
+#include "arm_compute/core/Window.h"
+#include "arm_compute/runtime/CL/CLScheduler.h"
+#include "arm_compute/runtime/CL/CLSubTensor.h"
+#include "arm_compute/runtime/CL/CLTensor.h"
+#include "arm_compute/runtime/CL/CLTensorAllocator.h"
+
+#include "arm_compute/core/CL/ICLTensor.h"
+
+#include "boost_wrapper.h"
+
+#include <random>
+#include <string>
+
+using namespace arm_compute;
+using namespace arm_compute::test;
+using namespace arm_compute::test::cl;
+using namespace arm_compute::test::validation;
+
+namespace
+{
+const float tolerance_exp     = 1.0f; /**< Tolerance value for comparing reference's output against implementation's output  (exponential)*/
+const float tolerance_invsqrt = 4.0f; /**< Tolerance value for comparing reference's output against implementation's output (inverse square-root) */
+const float tolerance_log     = 5.0f; /**< Tolerance value for comparing reference's output against implementation's output (logarithm) */
+
+/** Compute Neon fixed point operation for signed 8bit fixed point.
+ *
+ * @param[in] shape Shape of the input and output tensors.
+ *
+ * @return Computed output tensor.
+ */
+CLTensor compute_fixed_point_op(const TensorShape &shape, int fixed_point_position, FixedPointOp op)
+{
+    std::string fixed_point_operation_kernel;
+#ifndef EMBEDDED_KERNELS
+    fixed_point_operation_kernel += "#include \"fixed_point.h\"\n";
+#endif
+    fixed_point_operation_kernel +=
+        "__kernel void fixed_point_operation_qs8(                                                                 \n"
+        "   __global char* src,                                                                                   \n"
+        "   __global char* dst)                                                                                   \n"
+        "{                                                                                                        \n"
+        "   char16 in = vload16(0, src + get_global_id(0) * 16);                                                  \n"
+        "   if(FIXED_POINT_OP == 0)                                                                               \n"
+        "   {                                                                                                     \n"
+        "       vstore16(EXP_OP_EXPAND(in, DATA_TYPE, 16, FIXED_POINT_POS), 0, dst + get_global_id(0) * 16);      \n"
+        "   }                                                                                                     \n"
+        "   else if(FIXED_POINT_OP == 1)                                                                          \n"
+        "   {                                                                                                     \n"
+        "       vstore16(INVSQRT_OP_EXPAND(in, DATA_TYPE, 16, FIXED_POINT_POS), 0, dst + get_global_id(0) * 16);  \n"
+        "   }                                                                                                     \n"
+        "   else                                                                                                  \n"
+        "   {                                                                                                     \n"
+        "       vstore16(LOG_OP_EXPAND(in, DATA_TYPE, 16, FIXED_POINT_POS), 0, dst + get_global_id(0) * 16);      \n"
+        "   }                                                                                                     \n"
+        "}                                                                                                        \n"
+        "\n";
+
+    // Create tensors
+    CLTensor src = create_tensor<CLTensor>(shape, DataType::QS8, 1, fixed_point_position);
+    CLTensor dst = create_tensor<CLTensor>(shape, DataType::QS8, 1, fixed_point_position);
+
+    // Allocate tensors
+    src.allocator()->allocate();
+    dst.allocator()->allocate();
+
+    BOOST_TEST(!src.info()->is_resizable());
+    BOOST_TEST(!dst.info()->is_resizable());
+
+    // Set build options
+    std::string build_opts = "-DFIXED_POINT_POS=" + val_to_string<int>(fixed_point_position);
+    build_opts += " -DDATA_TYPE=qs8";
+
+    // Fill tensors.
+    int min = 0;
+    int max = 0;
+    switch(op)
+    {
+        case FixedPointOp::EXP:
+            min = -(1 << (fixed_point_position - 1));
+            max = (1 << (fixed_point_position - 1));
+            build_opts += " -DFIXED_POINT_OP=0";
+            break;
+        case FixedPointOp::INV_SQRT:
+            min = 1;
+            max = 0x7F;
+            build_opts += " -DFIXED_POINT_OP=1";
+            break;
+        case FixedPointOp::LOG:
+            min = (1 << (fixed_point_position - 1));
+            max = 0x3F;
+            build_opts += " -DFIXED_POINT_OP=2";
+            break;
+        default:
+            ARM_COMPUTE_ERROR("Operation not supported");
+    }
+
+    std::uniform_int_distribution<> distribution(min, max);
+    library->fill(CLAccessor(src), distribution, 0);
+
+    std::vector<std::string> sources;
+
+#ifndef EMBEDDED_KERNELS
+    build_opts += " -I" + CLKernelLibrary::get().get_kernel_path();
+#else
+    sources.push_back(CLKernelLibrary::get().get_program_source("fixed_point.h"));
+#endif /* EMBEDDED_KERNELS */
+
+    sources.push_back(fixed_point_operation_kernel);
+
+    // Create program
+    ::cl::Program program = ::cl::Program(sources);
+
+    // Build program
+    program.build(build_opts.c_str());
+
+    ::cl::Kernel kernel = ::cl::Kernel(program, "fixed_point_operation_qs8", nullptr);
+
+    unsigned int idx = 0;
+    kernel.setArg(idx++, src.cl_buffer());
+    kernel.setArg(idx++, dst.cl_buffer());
+
+    ::cl::NDRange gws(shape[0] / 16, 1, 1);
+    CLScheduler::get().queue().enqueueNDRangeKernel(kernel, 0, gws);
+
+    return dst;
+}
+} // namespace
+
+#ifndef DOXYGEN_SKIP_THIS
+BOOST_AUTO_TEST_SUITE(CL)
+BOOST_AUTO_TEST_SUITE(FixedPoint)
+BOOST_AUTO_TEST_SUITE(QS8)
+
+BOOST_AUTO_TEST_SUITE(Exp)
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 6), shape, fixed_point_position)
+{
+    // Compute function
+    CLTensor dst = compute_fixed_point_op(shape, fixed_point_position, FixedPointOp::EXP);
+
+    // Compute reference
+    RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::EXP, fixed_point_position);
+
+    // Validate output
+    validate(CLAccessor(dst), ref_dst, tolerance_exp);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(Log)
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(3, 6), shape, fixed_point_position)
+{
+    // Compute function
+    CLTensor dst = compute_fixed_point_op(shape, fixed_point_position, FixedPointOp::LOG);
+
+    // Compute reference
+    RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::LOG, fixed_point_position);
+
+    // Validate output
+    validate(CLAccessor(dst), ref_dst, tolerance_log);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(Invsqrt)
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 6), shape, fixed_point_position)
+{
+    // Compute function
+    CLTensor dst = compute_fixed_point_op(shape, fixed_point_position, FixedPointOp::INV_SQRT);
+
+    // Compute reference
+    RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::INV_SQRT, fixed_point_position);
+
+    // Validate output
+    validate(CLAccessor(dst), ref_dst, tolerance_invsqrt);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+#endif