aboutsummaryrefslogtreecommitdiff
path: root/compute_kernel_writer
diff options
context:
space:
mode:
Diffstat (limited to 'compute_kernel_writer')
-rw-r--r--compute_kernel_writer/CMakeLists.txt189
-rw-r--r--compute_kernel_writer/README.md97
-rw-r--r--compute_kernel_writer/include/ckw/Error.h131
-rw-r--r--compute_kernel_writer/include/ckw/Kernel.h76
-rw-r--r--compute_kernel_writer/include/ckw/KernelArgument.h99
-rw-r--r--compute_kernel_writer/include/ckw/KernelWriter.h418
-rw-r--r--compute_kernel_writer/include/ckw/TensorInfo.h96
-rw-r--r--compute_kernel_writer/include/ckw/TensorOperand.h109
-rw-r--r--compute_kernel_writer/include/ckw/TensorSampler.h102
-rw-r--r--compute_kernel_writer/include/ckw/TileInfo.h92
-rw-r--r--compute_kernel_writer/include/ckw/TileOperand.h112
-rw-r--r--compute_kernel_writer/include/ckw/types/ConstantData.h93
-rw-r--r--compute_kernel_writer/include/ckw/types/ConvertPolicy.h41
-rw-r--r--compute_kernel_writer/include/ckw/types/DataType.h50
-rw-r--r--compute_kernel_writer/include/ckw/types/MemoryOperation.h37
-rw-r--r--compute_kernel_writer/include/ckw/types/Operators.h101
-rw-r--r--compute_kernel_writer/include/ckw/types/TargetArchitecture.h40
-rw-r--r--compute_kernel_writer/include/ckw/types/TargetLanguage.h40
-rw-r--r--compute_kernel_writer/include/ckw/types/TensorComponentType.h61
-rw-r--r--compute_kernel_writer/include/ckw/types/TensorDataLayout.h52
-rw-r--r--compute_kernel_writer/include/ckw/types/TensorSamplerTypes.h84
-rw-r--r--compute_kernel_writer/include/ckw/types/TensorStorageType.h46
-rw-r--r--compute_kernel_writer/src/Error.cpp41
-rw-r--r--compute_kernel_writer/src/Helpers.cpp63
-rw-r--r--compute_kernel_writer/src/Helpers.h56
-rw-r--r--compute_kernel_writer/src/ITensor.h46
-rw-r--r--compute_kernel_writer/src/ITensorArgument.h135
-rw-r--r--compute_kernel_writer/src/ITensorComponent.h54
-rw-r--r--compute_kernel_writer/src/ITile.cpp35
-rw-r--r--compute_kernel_writer/src/ITile.h141
-rw-r--r--compute_kernel_writer/src/Kernel.cpp54
-rw-r--r--compute_kernel_writer/src/KernelArgument.cpp68
-rw-r--r--compute_kernel_writer/src/KernelWriter.cpp124
-rw-r--r--compute_kernel_writer/src/Tensor3dMapper.cpp155
-rw-r--r--compute_kernel_writer/src/Tensor3dMapper.h82
-rw-r--r--compute_kernel_writer/src/TensorInfo.cpp77
-rw-r--r--compute_kernel_writer/src/TensorOperand.cpp135
-rw-r--r--compute_kernel_writer/src/TensorSampler.cpp108
-rw-r--r--compute_kernel_writer/src/TensorUtils.cpp116
-rw-r--r--compute_kernel_writer/src/TensorUtils.h57
-rw-r--r--compute_kernel_writer/src/TileInfo.cpp73
-rw-r--r--compute_kernel_writer/src/TileOperand.cpp89
-rw-r--r--compute_kernel_writer/src/TileView.cpp57
-rw-r--r--compute_kernel_writer/src/TileView.h209
-rw-r--r--compute_kernel_writer/src/cl/CLHelpers.cpp353
-rw-r--r--compute_kernel_writer/src/cl/CLHelpers.h138
-rw-r--r--compute_kernel_writer/src/cl/CLKernelWriter.cpp833
-rw-r--r--compute_kernel_writer/src/cl/CLKernelWriter.h261
-rw-r--r--compute_kernel_writer/src/cl/CLTensorArgument.cpp207
-rw-r--r--compute_kernel_writer/src/cl/CLTensorArgument.h89
-rw-r--r--compute_kernel_writer/src/cl/CLTensorComponent.cpp126
-rw-r--r--compute_kernel_writer/src/cl/CLTensorComponent.h81
-rw-r--r--compute_kernel_writer/src/cl/CLTile.cpp234
-rw-r--r--compute_kernel_writer/src/cl/CLTile.h86
-rw-r--r--compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.cpp353
-rw-r--r--compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.h108
-rw-r--r--compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.cpp213
-rw-r--r--compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.h89
-rw-r--r--compute_kernel_writer/src/cl/helpers/ICLMemoryOpHelper.h121
-rw-r--r--compute_kernel_writer/src/types/ConstantData.cpp141
-rw-r--r--compute_kernel_writer/src/types/DataTypeHelpers.cpp35
-rw-r--r--compute_kernel_writer/src/types/DataTypeHelpers.h43
-rw-r--r--compute_kernel_writer/src/types/TensorComponentType.h78
-rw-r--r--compute_kernel_writer/validation/Validation.cpp166
-rw-r--r--compute_kernel_writer/validation/tests/CLConstantTileTest.hpp371
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterAssignTest.h101
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterBinaryOpTest.h127
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterCastTest.h104
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterCommentTest.h74
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterDeclareConstantTileTest.h106
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterDeclareTensorTest.h115
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterDeclareTileTest.h99
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterForTest.h85
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterGetGlobalIdTest.h72
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterIfTest.h175
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterOpLoadIndirectTest.h216
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterOpLoadStoreTest.h325
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterPrintTest.h75
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterReturnTest.h67
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterSubTileTest.h264
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterTernaryOpTest.h111
-rw-r--r--compute_kernel_writer/validation/tests/CLKernelWriterUnaryExpressionTest.h105
-rw-r--r--compute_kernel_writer/validation/tests/CLTensorArgumentTest.h540
-rw-r--r--compute_kernel_writer/validation/tests/CLTileTest.hpp467
-rw-r--r--compute_kernel_writer/validation/tests/TensorBitMaskTest.h221
-rw-r--r--compute_kernel_writer/validation/tests/UtilsTest.h104
-rw-r--r--compute_kernel_writer/validation/tests/common/Common.h71
-rw-r--r--compute_kernel_writer/validation/tests/common/KernelWriterInterceptor.h90
88 files changed, 11981 insertions, 0 deletions
diff --git a/compute_kernel_writer/CMakeLists.txt b/compute_kernel_writer/CMakeLists.txt
new file mode 100644
index 0000000000..69a4cdd51f
--- /dev/null
+++ b/compute_kernel_writer/CMakeLists.txt
@@ -0,0 +1,189 @@
+# Copyright (c) 2023 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.
+
+cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
+
+#---------------------------------------------------------------------
+# Compute Kernel Writer Project
+
+project(ComputeKernelWriter
+ VERSION 1.0.0
+ LANGUAGES CXX
+)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+include(GNUInstallDirs)
+
+message(STATUS "${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_VERSION}")
+
+#---------------------------------------------------------------------
+# Options
+
+option(CKW_ENABLE_OPENCL "Enable OpenCL code generation" OFF)
+option(CKW_ENABLE_ASSERTS "Enable assertions. Always enabled in Debug builds" OFF)
+option(CKW_BUILD_TESTING "Build the Compute Kernel Writer validation test suite" OFF)
+option(CKW_BUILD_PROTOTYPE "Build the prototype implementation of kernel writer." OFF)
+option(CKW_CCACHE "Use compiler cache for faster recompilation" OFF)
+
+#---------------------------------------------------------------------
+# Build configuration
+
+get_property(CKW_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+
+# Allow only Release or Debug builds
+if(NOT CKW_IS_MULTI_CONFIG) # Single-config generators
+ if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Options: Release (default) or Debug" FORCE)
+ endif()
+else() # Multi-config generators
+ list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES RelWithDebInfo MinSizeRel)
+endif()
+
+# Simplistic CCache setup
+if(CKW_CCACHE)
+ find_program(CCACHE_FOUND ccache)
+ if(CCACHE_FOUND)
+ set(CMAKE_C_COMPILER_LAUNCHER ${CACHE_FOUND})
+ set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_FOUND})
+ endif()
+endif()
+
+#---------------------------------------------------------------------
+# Library targets
+
+set(CKW_CXX_FLAGS
+ -Wall
+ -Werror
+ -Wextra
+ -Wdisabled-optimization
+ -Wformat=2
+ -Winit-self
+ -Wstrict-overflow=2
+ -Wswitch-default
+ -Woverloaded-virtual
+ -Wformat-security
+ -Wctor-dtor-privacy
+ -Wsign-promo
+ -Weffc++
+ -pedantic
+)
+set(GNU_WARNINGS
+ -Wlogical-op
+ -Wstrict-null-sentinel
+)
+set(CKW_ASSERTS_OPTS
+ -fstack-protector-strong
+)
+
+add_library(ckw)
+target_compile_options(ckw
+ PUBLIC
+ ${CKW_CXX_FLAGS}
+ "$<$<CXX_COMPILER_ID:GNU>:${GNU_WARNINGS}>"
+ "$<$<CONFIG:Debug>:${CKW_ASSERTS_OPTS}>"
+ "$<$<BOOL:${CKW_ENABLE_ASSERTS}>:${CKW_ASSERTS_OPTS}>"
+ # Set CMAKE_CXX_FLAGS last so user can overwrite options
+ ${CMAKE_CXX_FLAGS}
+ PRIVATE
+ # Always optimize for binary size
+ $<$<CONFIG:Release>:-Os>
+)
+
+target_compile_definitions(ckw PUBLIC
+ $<$<CONFIG:Debug>:COMPUTE_KERNEL_WRITER_DEBUG_ENABLED>
+ $<$<CONFIG:Debug>:COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED>
+ $<$<BOOL:${CKW_ENABLE_ASSERTS}>:COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED>
+ $<$<BOOL:${CKW_ENABLE_OPENCL}>:COMPUTE_KERNEL_WRITER_OPENCL_ENABLED>
+)
+
+target_sources(ckw PRIVATE
+ src/types/ConstantData.cpp
+ src/types/DataTypeHelpers.cpp
+ src/Error.cpp
+ src/Helpers.cpp
+ src/ITile.cpp
+ src/Kernel.cpp
+ src/KernelArgument.cpp
+ src/KernelWriter.cpp
+ src/Tensor3dMapper.cpp
+ src/TensorInfo.cpp
+ src/TensorOperand.cpp
+ src/TensorSampler.cpp
+ src/TensorUtils.cpp
+ src/TileInfo.cpp
+ src/TileOperand.cpp
+ src/TileView.cpp
+)
+
+if(CKW_ENABLE_OPENCL)
+ target_sources(ckw PRIVATE
+ src/cl/CLTensorArgument.cpp
+ src/cl/CLTensorComponent.cpp
+ src/cl/CLHelpers.cpp
+ src/cl/CLTile.cpp
+ src/cl/CLKernelWriter.cpp
+ src/cl/helpers/CLMemoryOpBufferHelper.cpp
+ src/cl/helpers/CLMemoryOpImage2dHelper.cpp
+ )
+endif()
+
+target_include_directories(ckw
+ PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include
+ PRIVATE ${CMAKE_CURRENT_LIST_DIR}
+)
+
+#---------------------------------------------------------------------
+# Validation tests
+
+if(CKW_BUILD_TESTING)
+ add_executable(ckw_validation
+ validation/Validation.cpp
+ )
+
+ target_link_libraries(ckw_validation PRIVATE ckw)
+ target_include_directories(ckw_validation
+ PRIVATE ${CMAKE_CURRENT_LIST_DIR}
+ )
+endif()
+
+#---------------------------------------------------------------------
+# Prototype
+
+if(CKW_BUILD_PROTOTYPE)
+ add_subdirectory(prototype)
+endif()
+
+#---------------------------------------------------------------------
+# Installing
+
+install(TARGETS ckw
+ CONFIGURATIONS Release
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+install(DIRECTORY include/ckw
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
diff --git a/compute_kernel_writer/README.md b/compute_kernel_writer/README.md
new file mode 100644
index 0000000000..2c7636ca9f
--- /dev/null
+++ b/compute_kernel_writer/README.md
@@ -0,0 +1,97 @@
+# Compute Kernel Writer
+
+Compute Kernel Writer is a tile-based, just-in-time code writer for deep learning and computer vision applications.
+This tool offers a C++ interface to allow developers to write functions without a return type (called "kernels")
+using their preferred programming language (at the moment, only OpenCL is supported).
+The library is specifically designed to be lightweight and to offer an intuitive API for efficient code writing.
+
+## Getting started
+
+The fastest way to get started with Compute Kernel Writer is to build and run the test suite.
+The following subsections show you how to do this.
+
+### Dependencies
+
+This project requires the following dependencies, obtainable via your preferred package manager, to be installed and
+available on your system.
+
+* `build-essential`
+* `cmake >= 3.14`
+* (Optional) `ninja-build`
+
+In addition, the guide makes use of the following toolchains:
+
+* (Optional) `Arm GNU toolchain` available to download from
+ the [Arm Developer](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) website
+* (Optional) `Android NDK toolset` available to download from
+ the [Android Developer](https://developer.android.com/ndk/downloads/index.html) website
+
+### Building and running tests
+
+#### Native compilation
+
+You can quickly compile the library on your computer by using the following commands:
+
+```shell
+mkdir -p build && cd build
+CXX=g++ cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCKW_ENABLE_OPENCL=ON -DCKW_ENABLE_ASSERTS=ON -DCKW_BUILD_TESTING=ON -S ..
+cmake --build .
+```
+
+The preceding commands build the library in release mode (`-DCMAKE_BUILD_TYPE=Release`) and targets OpenCL code
+generation (`-DCKW_ENABLE_OPENCL=ON`).
+In addition, code assertions are enabled (`-DCKW_ENABLE_ASSERTS=ON`) and the test suite is
+built (`-DCKW_BUILD_TESTING=ON`).
+Alternatively, choose to build a static instead of a shared library by setting `-DBUILD_SHARED_LIBS=OFF`.
+
+#### Cross-compile to Linux AArch64
+
+The Arm GNU toolchain can be used to cross-compile the project to a Linux system with an AArch64 processor, like a
+Raspberry Pi, using an x86_64 Linux host machine.
+
+```shell
+mkdir -p build && cd build
+CXX=aarch64-none-linux-gnu-g++ cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCKW_ENABLE_OPENCL=ON -DCKW_ENABLE_ASSERTS=ON -DCKW_BUILD_TESTING=ON -S ..
+cmake --build .
+```
+
+The build configuration is identical to the previous step but now requires specifying the target triple in the CXX
+compiler (`CXX=aarch64-none-linux-gnu-g++`) to generate binaries for the target platform.
+
+#### Cross-compile to Android AArch64
+
+Cross-compiling for Android systems requires the Android NDK toolset. The downloaded NDK contains the toolchain file
+necessary for cross-compiling the project.
+
+```shell
+mkdir -p build && cd build
+cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCKW_ENABLE_OPENCL=ON -DCKW_ENABLE_ASSERTS=ON -DCKW_BUILD_TESTING=ON -DCMAKE_TOOLCHAIN_FILE=<NDK>/build/cmake/android.toolchain.cmake -S ..
+cmake --build .
+```
+
+This build re-uses the same build configuration as before, but this time does not require specifying the CXX compiler as
+this (and other target-specific information) is handled by the toolchain file (`-DCMAKE_TOOLCHAIN_FILE`).
+
+#### Run the validation test suite
+
+Confirm the project has been built successfully by running the validation test suite.
+
+```shell
+./ckw_validation
+```
+
+### List of build options
+
+This project can be configured with the following build options. Enable options by passing them to the CMake command,
+preceded with `-D`.
+
+| Option | Description |
+|:---------------------|:------------------------------------------------------------------------------------------------------------------------------------------|
+| BUILD_SHARED_LIBS | Controls whether to build static or shared libraries. |
+| CMAKE_BUILD_TYPE | The project build type or configuration. Choose from Release or Debug. <br/>The release build will always build for smallest binary size. |
+| CKW_ENABLE_OPENCL | Enable OpenCL code generation. |
+| CKW_ENABLE_ASSERTS | Enable assertions. Always enabled for Debug builds. |
+| CKW_BUILD_TESTING | Build the validation test suite. |
+| CKW_BUILD_PROTOTYPE | Build the prototype implementation. |
+| CKW_CCACHE | Use compiler cache for faster recompilation. |
+| CMAKE_TOOLCHAIN_FILE | When cross-compiling, set this variable to the path of the CMake toolchain file. |
diff --git a/compute_kernel_writer/include/ckw/Error.h b/compute_kernel_writer/include/ckw/Error.h
new file mode 100644
index 0000000000..6b80778957
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/Error.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef CKW_INCLUDE_CKW_ERROR_H
+#define CKW_INCLUDE_CKW_ERROR_H
+
+#include <stdexcept>
+#include <string>
+
+namespace ckw
+{
+/** Creates the error message
+ *
+ * @param[in] file File in which the error occurred.
+ * @param[in] func Function in which the error occurred.
+ * @param[in] line Line in which the error occurred.
+ * @param[in] msg Message to display before abandoning.
+ *
+ * @return status containing the error
+ */
+std::string
+create_error_msg(const std::string &file, const std::string &func, const std::string &line, const std::string &msg);
+
+/** Print the given message then throw an std::runtime_error.
+ *
+ * @param[in] msg Message to display.
+ */
+#define COMPUTE_KERNEL_WRITER_ERROR_ON_MSG(msg) \
+ do \
+ { \
+ const std::string arg0(__FILE__); \
+ const std::string arg1(__func__); \
+ const std::string arg2(std::to_string(__LINE__)); \
+ const std::string arg3(msg); \
+ std::runtime_error(create_error_msg(arg0, arg1, arg2, arg3)); \
+ } while (false)
+
+/** Mark the variables as unused.
+ *
+ * @param[in] ... Variables which are unused.
+ */
+#define CKW_UNUSED(...) ckw::ignore_unused(__VA_ARGS__) // NOLINT
+
+/** Mark the variables as unused.
+ *
+ * @param[in] ... Variables which are unused.
+ */
+template <typename... T>
+inline void ignore_unused(T &&...)
+{
+}
+
+/** Throw an std::runtime_error with the specified message.
+ *
+ * @param[in] msg The error message.
+ */
+#define CKW_THROW_MSG(msg) \
+ do \
+ { \
+ const std::string file(__FILE__); \
+ const std::string func(__func__); \
+ const std::string line(std::to_string(__LINE__)); \
+ const std::string message(msg); \
+ \
+ throw std::runtime_error(ckw::create_error_msg(file, func, line, message)); \
+ } while (false)
+
+#ifdef COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+
+/** If the condition is not met, throw an std::runtime_error with the specified message if assertion is enabled.
+ *
+ * @param[in] cond The condition that is expected to be true.
+ * @param[in] msg The error message when the condition is not met.
+ */
+#define CKW_ASSERT_MSG(cond, msg) \
+ do \
+ { \
+ if (!(cond)) \
+ { \
+ CKW_THROW_MSG(msg); \
+ } \
+ } while (false)
+
+#else // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+
+#define CKW_ASSERT_MSG(cond, msg)
+
+#endif // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+
+/** If the condition is not met, throw an std::runtime_error if assertion is enabled.
+ *
+ * @param[in] cond The condition that is expected to be true.
+ */
+#define CKW_ASSERT(cond) CKW_ASSERT_MSG(cond, #cond)
+
+/** If the precondition is met but the condition is not met, throw an std::runtime_error if assertion is enabled.
+ *
+ * @param[in] precond The precondition that triggers the check.
+ * @param[in] cond The condition that is expected to be true if precondition is true.
+ */
+#define CKW_ASSERT_IF(precond, cond) CKW_ASSERT(!(precond) || (cond))
+
+/** Throw an std::runtime_error with the specified message if assertion is enabled.
+ *
+ * @param[in] msg The error message when the condition is not met.
+ */
+#define CKW_ASSERT_FAILED_MSG(msg) CKW_ASSERT_MSG(false, msg)
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_ERROR_H
diff --git a/compute_kernel_writer/include/ckw/Kernel.h b/compute_kernel_writer/include/ckw/Kernel.h
new file mode 100644
index 0000000000..f9b7bbb82e
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/Kernel.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_KERNEL_H
+#define CKW_INCLUDE_CKW_KERNEL_H
+
+#include "ckw/KernelArgument.h"
+
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+
+// Forward Declerations
+class TileInfo;
+class TileOperand;
+
+enum class TargetLanguage;
+
+/** The kernel that has been emitted by the kernel writer.
+ *
+ * It contains all the necessary information to compile and execute the kernel.
+ */
+class Kernel
+{
+public:
+ virtual ~Kernel();
+
+ /** Initialize a new instance of @ref Kernel class with all emitted kernel information.
+ *
+ * @param[in] language The target language of the kernel.
+ * @param[in] arguments The list of kernel arguments.
+ * @param[in] source_code The source code of the kernel.
+ */
+ Kernel(TargetLanguage language, const std::vector<KernelArgument> &arguments, const std::string &source_code);
+
+ /** Get the target language. */
+ TargetLanguage target_language() const;
+
+ /** Get the list of arguments. */
+ const std::vector<KernelArgument> &arguments() const;
+
+ /** Get the source code. */
+ const std::string &source_code() const;
+
+private:
+ TargetLanguage _language;
+ std::vector<KernelArgument> _arguments;
+ std::string _source_code;
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_KERNEL_H
diff --git a/compute_kernel_writer/include/ckw/KernelArgument.h b/compute_kernel_writer/include/ckw/KernelArgument.h
new file mode 100644
index 0000000000..7e9bcbf1ee
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/KernelArgument.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_KERNELARGUMENT_H
+#define CKW_INCLUDE_CKW_KERNELARGUMENT_H
+
+#include "ckw/types/TensorComponentType.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** A kernel argument which can be either a tensor storage or a tensor component. */
+class KernelArgument
+{
+public:
+ /** The type of kernel argument. */
+ enum class Type : int32_t
+ {
+ /** The argument that provides the read and/or write access to the tensor data.
+ *
+ * See @ref ckw::TensorStorageType to see the list of supported storage type.
+ */
+ TensorStorage,
+
+ /** The argument that provides extra information about the tensor.
+ *
+ * See @ref ckw::TensorComponentType to see the list of supported component.
+ */
+ TensorComponent,
+ };
+
+ /** Initialize a new instance of kernel argument class for a tensor storage argument. */
+ KernelArgument(int32_t tensor_id, TensorStorageType storage_type);
+
+ /** Initialize a new instance of kernel argument class for a tensor component argument. */
+ KernelArgument(int32_t tensor_id, TensorComponentType component_type);
+
+ /** Get the type of kernel argument. */
+ Type type() const;
+
+ /** Get the argument ID.
+ *
+ * This method can be used to get the tensor info ID of both tensor storage and tensor component arguments.
+ */
+ int32_t id() const;
+
+ /** Get the type of tensor storage.
+ *
+ * This method can only be used for tensor storage argument.
+ */
+ TensorStorageType tensor_storage_type() const;
+
+ /** Get the tensor component type.
+ *
+ * This method can only be used for tensor component argument.
+ */
+ TensorComponentType tensor_component_type() const;
+
+private:
+ Type _type;
+ int32_t _id;
+
+ union SubId
+ {
+ int32_t unknown;
+ TensorStorageType tensor_storage_type;
+ TensorComponentType tensor_component_type;
+ };
+
+ SubId _sub_id{0};
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_KERNELARGUMENT_H
diff --git a/compute_kernel_writer/include/ckw/KernelWriter.h b/compute_kernel_writer/include/ckw/KernelWriter.h
new file mode 100644
index 0000000000..da41b940d7
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/KernelWriter.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_KERNELWRITER_H
+#define CKW_INCLUDE_CKW_KERNELWRITER_H
+
+#include "ckw/Kernel.h"
+#include "ckw/TensorInfo.h"
+#include "ckw/TensorOperand.h"
+#include "ckw/TensorSampler.h"
+#include "ckw/TileInfo.h"
+#include "ckw/TileOperand.h"
+#include "ckw/types/ConstantData.h"
+#include "ckw/types/ConvertPolicy.h"
+#include "ckw/types/DataType.h"
+#include "ckw/types/Operators.h"
+#include "ckw/types/TargetArchitecture.h"
+#include "ckw/types/TargetLanguage.h"
+#include "ckw/types/TensorComponentType.h"
+#include "ckw/types/TensorDataLayout.h"
+#include "ckw/types/TensorSamplerTypes.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <tuple>
+
+namespace ckw
+{
+
+/** Forward Declarations */
+class TileArea;
+
+/** A kernel writer.
+ *
+ * This class is used to construct a new kernel by defining arguments, declaring variable and writing code.
+ *
+ * Use @ref KernelWriter::create_instance method to create the kernel writer for the specific target architecture and language.
+ *
+ * After having finished constructing the kernel, call @ref KernelWriter::emit_kernel to get the kernel object.
+ */
+class KernelWriter
+{
+public:
+ // =============================================================================================
+ // Construtors and destructor
+ // =============================================================================================
+
+ /** Initialize a new instance of @ref KernelWriter class for the specific architecture and language.
+ *
+ * Supported target architectures and languages:
+ *
+ * Architecture | Languages |
+ * ------------------------------|------------------------------|
+ * GpuArmMaliValhall | OpenCL |
+ *
+ * @param[in] architecture The architecture on which the kernel is executed.
+ * @param[in] language The language to write the kernel.
+ */
+ static std::unique_ptr<KernelWriter> create_instance(TargetArchitecture architecture, TargetLanguage language);
+
+ /** Destructor */
+ virtual ~KernelWriter();
+
+ // =============================================================================================
+ // Data processing
+ // =============================================================================================
+
+ /** Write assignment statement: `<dst> = <src>;`.
+ *
+ * @param[in] dst The destination tile.
+ * @param[in] src The source tile.
+ */
+ virtual void op_assign(const TileOperand &dst, const TileOperand &src) = 0;
+
+ /** Write the cast statement: `<dst> = convert_<dst.type><policy>(<src>);`.
+ *
+ * @param[in] dst The destination tile.
+ * @param[in] src The source tile.
+ * @param[in] policy The policy governing the behavior of the cast.
+ */
+ virtual void op_cast(const TileOperand &dst, const TileOperand &src, ConvertPolicy policy) = 0;
+
+ /** Write the unary expression statement: `<dst> = <op> <src>;`.
+ *
+ * @param[in] dst The destination tile.
+ * @param[in] op The unary operator.
+ * @param[in] src The source tile.
+ */
+ virtual void op_unary(const TileOperand &dst, UnaryOp op, const TileOperand &src) = 0;
+
+ /** Write the binary expression statement: `<dst> = <op>(<first>, <second>);`.
+ *
+ * @param[in] dst The destination tile.
+ * @param[in] op The binary operator.
+ * @param[in] first The first source tile.
+ * @param[in] second The second source tile.
+ */
+ virtual void
+ op_binary(const TileOperand &dst, BinaryOp op, const TileOperand &first, const TileOperand &second) = 0;
+
+ /** Write ternary expression statement: `<dst> = <op>(<first>, <second>, <third>);`.
+ *
+ * @param[in] dst The destination tile.
+ * @param[in] op The ternary operator.
+ * @param[in] first The first source tile.
+ * @param[in] second The second source tile.
+ * @param[in] third The third source tile.
+ */
+ virtual void op_ternary(const TileOperand &dst,
+ TernaryOp op,
+ const TileOperand &first,
+ const TileOperand &second,
+ const TileOperand &third) = 0;
+
+ // =============================================================================================
+ // Flow control
+ // =============================================================================================
+
+ /** Write if block: `if(<lhs> <op> <rhs>) { <body> }`.
+ *
+ * @param[in] lhs The LHS tile of the condition.
+ * @param[in] op The relational binary operator.
+ * @param[in] rhs The RHS tile of the condition.
+ * @param[in] body The function that writes the body of the if block.
+ */
+ virtual void
+ op_if(const TileOperand &lhs, BinaryOp op, const TileOperand &rhs, const std::function<void()> &body) = 0;
+
+ /** Write else-if block: `else if(<lhs> <op> <rhs>) { <body> }`.
+ *
+ * @param[in] lhs The LHS tile of the condition.
+ * @param[in] op The relational binary operator.
+ * @param[in] rhs The RHS tile of the condition.
+ * @param[in] body The function that writes the body of the else-if block.
+ */
+ virtual void
+ op_else_if(const TileOperand &lhs, BinaryOp op, const TileOperand &rhs, const std::function<void()> &body) = 0;
+
+ /** Write an else block: `else { <body> }`.
+ *
+ * @param[in] body The function that writes the body of the else block.
+ */
+ virtual void op_else(const std::function<void()> &body) = 0;
+
+ /** Write for-loop block: `for(; <var> <cond_op> <cond_value>; <update_var> <update_op> <update_value>) { body }`.
+ *
+ * @param[in] var The scalar tile used in loop condition.
+ * @param[in] cond_op The relational binary operator used in loop condition.
+ * @param[in] cond_value The value which the variable is compared against.
+ * @param[in] update_var The scalar tile which is updated each iteration.
+ * @param[in] update_op The assignment operator used for updating the update value.
+ * @param[in] update_value The value which is updated at every iteration.
+ * @param[in] body The function that writes the body of the for-loop block.
+ */
+ virtual void op_for_loop(const TileOperand &var,
+ BinaryOp cond_op,
+ const TileOperand &cond_value,
+ const TileOperand &update_var,
+ AssignmentOp update_op,
+ const TileOperand &update_value,
+ const std::function<void()> &body) = 0;
+
+ /** Write the return statement. */
+ virtual void op_return() = 0;
+
+ // =============================================================================================
+ // Misc
+ // =============================================================================================
+
+ /** Write the statement to get the global ID of the specified dimension.
+ *
+ * @param[in] dst The tile to write the global ID into.
+ * @param[in] dim The dimension.
+ */
+ virtual void op_get_global_id(const TileOperand &dst, int32_t dim) = 0;
+
+ /** Write the line comment in debug build.
+ *
+ * This function does not take effect on release build.
+ *
+ * The comment must only contain one line (i.e. no newline character is allowed).
+ *
+ * @param[in] text The comment to be written.
+ */
+ virtual void op_comment(const std::string &text) = 0;
+
+ /** Write the statement to print out the value of all the specified tiles.
+ *
+ * The printing statement is constructed so that the prefix and each of the operand are printed in separate lines.
+ * The format for each operand varies depending on whether it is a 2D tile, a vector or a scalar value.
+ *
+ * Example output of the printing statement when it is executed:
+ *
+ * prefix
+ * scalar_name = scalar_value
+ * vector_name = [vector_value_0, vector_value_1, vector_value_2]
+ * tile_name = [[tile_value_00, tile_value_01], [tile_value_10, tile_value_11]]
+ *
+ * @param[in] prefix The first string to be printed out before the list of operands.
+ * @param[in] operands The list of tiles to be included in the printing statement.
+ */
+ virtual void op_print(const std::string &prefix, const std::vector<TileOperand> &operands) = 0;
+
+ /** Write the given raw code to kernel source code
+ * It's used to address the cases where the user needs to
+ * explicitly add a code where it's not (yet) supported by
+ * the kernel writer utility calls.
+ *
+ * @param[in] raw_code raw code to write as string
+ */
+ virtual void op_write_raw_code(const std::string &raw_code) = 0;
+
+ // =============================================================================================
+ // Code generation
+ // =============================================================================================
+
+ /** Emit the kernel object.
+ *
+ * @param[in] name The name of the kernel object to be generated.
+ */
+ virtual std::unique_ptr<Kernel> emit_kernel(const std::string &name) = 0;
+
+ // =============================================================================================
+ // Tensor and tile declaration
+ // =============================================================================================
+
+ /** Declare a tensor argument.
+ *
+ * @param[in] name The name of the tensor.
+ * @param[in] info The tensor info.
+ *
+ * @return The @ref TensorOperand object.
+ */
+ virtual TensorOperand declare_tensor_argument(const std::string &name, const TensorInfo &info) = 0;
+
+ /** Declare a tile given its name and tile info
+ *
+ * @param[in] name Name of the tile
+ * @param[in] tile_info Shape and data type of the tile
+ *
+ * @return The created tile operand
+ */
+ virtual TileOperand declare_tile(const std::string &name, const TileInfo &tile_info) = 0;
+
+ /** Declare a constant tile given a @ref:ConstantData object
+ *
+ * @param[in] data a @ref ckw::ConstantData object that has the values and the
+ * underlying data type of the constant tile
+ *
+ * @return The created constant tile operand
+ */
+ virtual TileOperand declare_constant_tile(const ConstantData &data) = 0;
+
+ /** Load the data from the tensor memory to the tile using the sampling information.
+ *
+ * @param[in] tile_op The tile to be loaded.
+ * @param[in] tensor_op The tensor to be read.
+ * @param[in] sampler The tensor sampling information.
+ * @param[in] x x-coordinate
+ * @param[in] y y-coordinate
+ * @param[in] z z-coordinate
+ * @param[in] batch batch
+ */
+ virtual void op_load(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch) = 0;
+
+ /** Load the data from the tensor memory to the tile in a dilated way using the sampling information.
+ *
+ * Similar to @ref KernelWriter::op_load() and
+ *
+ * @param[in] dilation_x Dilation while reading in x-dimension
+ * @param[in] dilation_y Dilation while reading in y-dimension
+ */
+ virtual void op_load_dilated(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileOperand &dilation_x,
+ const TileOperand &dilation_y) = 0;
+
+ /** Store the data to the tensor memory from the tile using the sampling information.
+ *
+ * Similar to @ref KernelWriter::op_load()
+ */
+ virtual void op_store(const TensorOperand &tensor_op,
+ const TileOperand &tile_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch) = 0;
+
+ /** Store the data to the tensor memory from the tile in a dilated way using the sampling information.
+ *
+ * Similar to @ref KernelWriter::op_load_dilated()
+ */
+ virtual void op_store_dilated(const TensorOperand &tensor_op,
+ const TileOperand &tile_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileOperand &dilation_x,
+ const TileOperand &dilation_y) = 0;
+
+ /** Load the data from the tensor memory to the tile using the indirect buffer approach and respecting the sampling information.
+ *
+ * @param[in] tile_op The tile to be loaded.
+ * @param[in] tensor_op The tensor to be read.
+ * @param[in] sampler The tensor sampling information.
+ * @param[in] x x-coordinate
+ * @param[in] y y-coordinate
+ * @param[in] z z-coordinate
+ * @param[in] batch batch
+ */
+ virtual void op_load_indirect(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch_op) = 0;
+
+ // =============================================================================================
+ // ID space management
+ // =============================================================================================
+
+ /** Create the new unique ID space and return the value.
+ *
+ * This function changes the ID space to a new number which hasn't been used since the creation
+ * of this kernel writer object.
+ *
+ * @return The new ID space value.
+ */
+ int32_t new_id_space();
+
+ /** Get the current ID space. */
+ int32_t id_space() const;
+
+protected:
+ /** Set the current ID space.
+ *
+ * @param[in] value The ID space to be used.
+ */
+ KernelWriter &id_space(int32_t value);
+
+ /** Write the body code using the specified function.
+ *
+ * This function makes sure that a new ID space is created before and then is used solely
+ * by the specified body writing function.
+ * The ID space will not be reused after that.
+ *
+ * @param[in] body The function that writes the body code.
+ */
+ void write_body(const std::function<void()> &body);
+
+protected:
+ /** Generate full variable name by prefixing it with id space */
+ std::string generate_full_name(const std::string &name) const;
+
+ /** Create a new tile operand referring to the specified tile object. */
+ static TileOperand create_tile_operand(ITile &tile);
+
+ /** Get the reference to the tile object and the active area from the tile operand. */
+ static std::tuple<ITile &, TileArea> get_tile(const TileOperand &operand);
+
+ /** Create a new tensor operand from a tensor object. */
+ static TensorOperand create_tensor_operand(ITensor &tensor);
+
+ /** Get the reference to tensor object from the tensor operand. */
+ static ITensor &get_tensor(const TensorOperand &operand);
+
+ /** Get the values of a constant data object. */
+ static const std::vector<std::vector<std::string>> &get_values(const ConstantData &data);
+
+ /** Get the data type of a constant data object. */
+ static DataType get_data_type(const ConstantData &data);
+
+private:
+ int32_t _id_space{0};
+ int32_t _last_created_id_space{0};
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_KERNELWRITER_H
diff --git a/compute_kernel_writer/include/ckw/TensorInfo.h b/compute_kernel_writer/include/ckw/TensorInfo.h
new file mode 100644
index 0000000000..5c87cb5b12
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/TensorInfo.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TENSORINFO_H
+#define COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TENSORINFO_H
+
+#include "ckw/types/DataType.h"
+#include "ckw/types/TensorDataLayout.h"
+
+#include <array>
+#include <cstdint>
+
+namespace ckw
+{
+
+/** Compute Kernel Writer tensor shape
+ * The value -1 for the tensor dimension is reserved to dynamic dimensions.
+ */
+using TensorShape = std::array<int32_t, 5>;
+
+/** Tensor dimension value reserved to dynamic dimensions */
+constexpr int32_t kDynamicTensorDimensionValue = -1;
+
+/** Compute Kernel Writer tensor info */
+class TensorInfo
+{
+public:
+ /** Default constructor */
+ TensorInfo() = default;
+ /** Constructor
+ *
+ * @param[in] dt Tensor data type
+ * @param[in] shape Tensor shape
+ * @param[in] dl Tensor data layout
+ * @param[in] id Tensor id. The id is used to keep track of the user tensor binded. Through the id,
+ * the user can know what tensor has been used by the Compute Kernel Writer.
+ * Possible id values:
+ * - greater than or equal to 0: bind a user specific tensors
+ * - less than 0: bind a virtual tensor (tile)
+ */
+ TensorInfo(DataType dt, const TensorShape &shape, TensorDataLayout dl, int32_t id);
+
+ /** Set shape */
+ TensorInfo &shape(const TensorShape &shape);
+
+ /** Get shape */
+ TensorShape shape() const;
+
+ /** Set data type */
+ TensorInfo &data_type(DataType dt);
+
+ /** Get data type */
+ DataType data_type() const;
+
+ /** Set data layout */
+ TensorInfo &data_layout(TensorDataLayout dl);
+
+ /** Get data layout */
+ TensorDataLayout data_layout() const;
+
+ /** Set id */
+ TensorInfo &id(int32_t id);
+
+ /** Get layout */
+ int32_t id() const;
+
+private:
+ TensorShape _shape{{0}};
+ DataType _dt{DataType::Unknown};
+ TensorDataLayout _dl{TensorDataLayout::Unknown};
+ int32_t _id{-1};
+};
+} // namespace ckw
+
+#endif /* COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TENSORINFO_H */
diff --git a/compute_kernel_writer/include/ckw/TensorOperand.h b/compute_kernel_writer/include/ckw/TensorOperand.h
new file mode 100644
index 0000000000..a3e53d1314
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/TensorOperand.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TENSOROPERAND_H
+#define CKW_INCLUDE_CKW_TENSOROPERAND_H
+
+#include "ckw/TileOperand.h"
+
+namespace ckw
+{
+
+class ITensor;
+class TensorInfo;
+
+/** A tensor operand provides access to the tensor info, tensor storages for load/store operations
+ * and tensor components (e.g. shape, strides, etc.) in the form of @ref TileOperand objects.
+ */
+class TensorOperand
+{
+public:
+ // _tensor field is completely hidden from the public API to avoid any misuse.
+ // Only kernel writer class interacts with tensor operand hence we allow it to access this field.
+ friend class KernelWriter;
+
+ /** Create an empty tensor operand.
+ *
+ * The new tensor operand doesn't refer to any tensor therefore it is not useable.
+ */
+ TensorOperand();
+
+ /** Check if the tensor operand contains a tensor and therefore useable. */
+ bool is_valid() const;
+
+ /** Get the tensor info. */
+ const TensorInfo &info() const;
+
+ /** Get the operand that contains the stride in dimension 0 of the tensor. */
+ TileOperand stride0();
+
+ /** Get the operand that contains the stride in dimension 1 of the tensor. */
+ TileOperand stride1();
+
+ /** Get the operand that contains the stride in dimension 2 of the tensor. */
+ TileOperand stride2();
+
+ /** Get the operand that contains the stride in dimension 3 of the tensor. */
+ TileOperand stride3();
+
+ /** Get the operand that contains the stride in dimension 4 of the tensor. */
+ TileOperand stride4();
+
+ /** Get the operand that contains the size of dimension 0 of the tensor. */
+ TileOperand dim0();
+
+ /** Get the operand that contains the size of dimension 1 of the tensor. */
+ TileOperand dim1();
+
+ /** Get the operand that contains the size of dimension 2 of the tensor. */
+ TileOperand dim2();
+
+ /** Get the operand that contains the size of dimension 3 of the tensor. */
+ TileOperand dim3();
+
+ /** Get the operand that contains the size of dimension 4 of the tensor. */
+ TileOperand dim4();
+
+ /** Get the operand that contains the size of dimensions 1 and 2 collapsed. */
+ TileOperand dim1_dim2();
+
+ /** Get the operand that contains the size of dimensions 1, 2 and 3 collapsed. */
+ TileOperand dim1_dim2_dim3();
+
+ /** Get the operand that contains the size of dimensions 2 and 3 collapsed. */
+ TileOperand dim2_dim3();
+
+ /** Get the operand that contains the offset in bytes to the first element. */
+ TileOperand offset_first_element_in_bytes();
+
+private:
+ /** Initialize a new instance of @ref TensorOperand class for a tensor. */
+ TensorOperand(ITensor &tensor);
+
+ ITensor *_tensor;
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TENSOROPERAND_H
diff --git a/compute_kernel_writer/include/ckw/TensorSampler.h b/compute_kernel_writer/include/ckw/TensorSampler.h
new file mode 100644
index 0000000000..117e8de2cf
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/TensorSampler.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TENSORSAMPLER_H
+#define CKW_INCLUDE_CKW_TENSORSAMPLER_H
+
+#include "ckw/types/TensorSamplerTypes.h"
+#include "ckw/types/TensorStorageType.h"
+
+namespace ckw
+{
+
+/** Tensor sampler
+ *
+ * It contains information about how the tensor is sampled. It can be used to
+ * tell how a tile should be stored to tensor memory, and how a tensor should be
+ * sampled to get the values stored in a tile. Where to sample the tensor is
+ * defined with the coordinates respecting the addressing modes, storage type and
+ * the tensor format defined in this class.
+ */
+class TensorSampler
+{
+public:
+ /** Initialize a new instance of @ref TensorSampler class. */
+ TensorSampler();
+
+ /** Initialize a new instance of @ref TensorSampler class.
+ *
+ * @param[in] storage Tensor storage to load/store the tensor from/to
+ * @param[in] format The tensor data format.
+ * @param[in] address_mode_x The address mode of the x dimension.
+ * @param[in] address_mode_y The address mode of the y dimension.
+ * @param[in] address_mode_z The address mode of the z dimension.
+ */
+ TensorSampler(TensorStorageType storage,
+ TensorSamplerFormat format,
+ TensorSamplerAddressModeX address_mode_x,
+ TensorSamplerAddressModeY address_mode_y,
+ TensorSamplerAddressModeZ address_mode_z);
+
+ /** Get the storage for the tensor */
+ TensorStorageType storage() const;
+
+ /** Set the storage for the tensor */
+ TensorSampler &storage(TensorStorageType storage);
+
+ /** Get the format of the tensor. */
+ TensorSamplerFormat format() const;
+
+ /** Set the format of the tensor. */
+ TensorSampler &format(TensorSamplerFormat format);
+
+ /** Get the address mode of the x dimension. */
+ TensorSamplerAddressModeX address_mode_x() const;
+
+ /** Set the address mode of the x dimension. */
+ TensorSampler &address_mode_x(TensorSamplerAddressModeX address_mode_x);
+
+ /** Get the address mode of the y dimension. */
+ TensorSamplerAddressModeY address_mode_y() const;
+
+ /** Set the address mode of the y dimension. */
+ TensorSampler &address_mode_y(TensorSamplerAddressModeY address_mode_y);
+
+ /** Get the address mode of the z dimension. */
+ TensorSamplerAddressModeZ address_mode_z() const;
+
+ /** Set the address mode of the z dimension. */
+ TensorSampler &address_mode_z(TensorSamplerAddressModeZ address_mode_z);
+
+private:
+ TensorStorageType _storage{TensorStorageType::BufferUint8Ptr};
+ TensorSamplerFormat _format{TensorSamplerFormat::Unknown};
+ TensorSamplerAddressModeX _address_mode_x{TensorSamplerAddressModeX::Unknown};
+ TensorSamplerAddressModeY _address_mode_y{TensorSamplerAddressModeY::Unknown};
+ TensorSamplerAddressModeZ _address_mode_z{TensorSamplerAddressModeZ::Unknown};
+};
+
+} // namespace ckw
+
+#endif // CKW_PROTOTYPE_INCLUDE_CKW_TENSORSAMPLER_H
diff --git a/compute_kernel_writer/include/ckw/TileInfo.h b/compute_kernel_writer/include/ckw/TileInfo.h
new file mode 100644
index 0000000000..678bb7aaf6
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/TileInfo.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TILEINFO
+#define COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TILEINFO
+
+#include "ckw/types/DataType.h"
+
+#include <array>
+#include <cstdint>
+
+namespace ckw
+{
+// Constants to access the tile width and height in the TileShape
+constexpr int32_t kTileWidthIdx = 0;
+constexpr int32_t kTileHeightIdx = 1;
+
+/** Compute Kernel Writer tile shape. It is used to define the shape of the tile */
+using TileShape = std::array<int32_t, 2>;
+
+/** Compute Kernel Writer tile info */
+class TileInfo
+{
+public:
+ /** Constructor used to initialize a scalar variable with a given data type
+ *
+ * @param[in] dt Tile data type
+ */
+ TileInfo(DataType dt);
+
+ /** Constructor used to initialize a vector with a given data type and vector length.
+ *
+ * @param[in] dt Tile data type
+ * @param[in] w Tile width (or vector length)
+ */
+ TileInfo(DataType dt, int32_t w);
+
+ /** Constructor used to initialize a tile with a given data type and tile sizes.
+ *
+ * @param[in] dt Tile data type
+ * @param[in] h Tile height
+ * @param[in] w Tile width
+ */
+ TileInfo(DataType dt, int32_t h, int32_t w);
+
+ /** Set width */
+ TileInfo &width(int32_t w);
+
+ /** Get width */
+ int32_t width() const;
+
+ /** Set height */
+ TileInfo &height(int32_t h);
+
+ /** Get height */
+ int32_t height() const;
+
+ /** Set data type */
+ TileInfo &data_type(DataType dt);
+
+ /** Get data type */
+ DataType data_type() const;
+
+private:
+ DataType _dt{DataType::Unknown};
+ TileShape _shape{};
+};
+
+} // namespace ckw
+
+#endif /* COMPUTE_KERNEL_WRITER_INCLUDE_CKW_TILEINFO */
diff --git a/compute_kernel_writer/include/ckw/TileOperand.h b/compute_kernel_writer/include/ckw/TileOperand.h
new file mode 100644
index 0000000000..556d589bc0
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/TileOperand.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TILEOPERAND_H
+#define CKW_INCLUDE_CKW_TILEOPERAND_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+class KernelWriter;
+class TensorOperand;
+class ITile;
+class TileInfo;
+
+/** A tile operand refers to a tile object that can be used for kernel writing. */
+class TileOperand
+{
+public:
+ // The constructor and _tile field is completely hidden from the public API to avoid any misuse.
+ // Only kernel writer and tensor operand classes create and interact with tile operand hence we allow them to access this field.
+ friend class KernelWriter;
+ friend class TensorOperand;
+
+ /** Create an empty tile operand.
+ *
+ * The new tile operand doesn't refer to any tile therefore it is not useable.
+ */
+ TileOperand();
+
+ /** Check if the tile operand contains a tile and therefore useable. */
+ bool is_valid() const;
+
+ /** Get the tile info. */
+ const TileInfo &tile_info() const;
+
+ /** Get a row vector of the current tile operand.
+ *
+ * @param[in] row The index of the row to be accessed in the current tile operand.
+ *
+ * @return A new tile operand referring to a row of the current tile operand.
+ */
+ TileOperand row(int32_t row) const;
+
+ /** Get a scalar element of the current tile operand.
+ *
+ * @param[in] row The index of the row to be accessed in the current tile operand.
+ * @param[in] col The index of the column to be accessed in the current tile operand.
+ *
+ * @return A new tile operand referring to a scalar element of the current tile operand.
+ */
+ TileOperand scalar(int32_t row, int32_t col) const;
+
+private:
+ // These are hidden from the public API to avoid any misuse.
+
+ /** Initialize a new instance of @ref TileOperand class for the given tile. */
+ TileOperand(ITile &tile);
+
+ /** Initialize a new instance of @ref TileOperand class that is the sub-tile of the given tile. */
+ TileOperand(const TileOperand &operand, int32_t row_start, int32_t row_end, int32_t col_start, int32_t col_end);
+
+ /** Get a sub-tile of the current tile operand.
+ *
+ * The range of rows and columns is defined by pairs of start and end indices, inclusive lower and exclusive upper.
+ * In other words, any row and column indices satisfying the following conditions will be part of the sub-tile:
+ *
+ * row_start <= row_index < row_end
+ * col_start <= col_index < col_end
+ *
+ * @param[in] row_start The start index of the row range.
+ * @param[in] row_end The end index of the row range.
+ * @param[in] col_start The start index of the column range.
+ * @param[in] col_end The end index of the column range.
+ *
+ * @return A new tile operand refering to the same tile but with the new active area.
+ */
+ TileOperand tile(int32_t row_start, int32_t row_end, int32_t col_start, int32_t col_end) const;
+
+ ITile *_tile;
+
+ int32_t _row_start;
+ int32_t _row_end;
+ int32_t _col_start;
+ int32_t _col_end;
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TILEOPERAND_H
diff --git a/compute_kernel_writer/include/ckw/types/ConstantData.h b/compute_kernel_writer/include/ckw/types/ConstantData.h
new file mode 100644
index 0000000000..ea95049c9e
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/ConstantData.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_CONSTANTDATA_H
+#define CKW_INCLUDE_CKW_TYPES_CONSTANTDATA_H
+
+#include "ckw/Error.h"
+#include "ckw/types/DataType.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <initializer_list>
+#include <iomanip>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace ckw
+{
+// Forward Declarations
+class KernelWriter;
+
+class ConstantData
+{
+ using String = std::string;
+ using StringVector = std::vector<String>;
+
+public:
+ /** Templated constructor */
+ template <typename T>
+ ConstantData(std::initializer_list<std::initializer_list<T>> values, DataType data_type);
+
+ /** Templated constructor */
+ template <typename T>
+ ConstantData(const std::vector<std::vector<T>> &values, DataType data_type);
+
+private:
+ /** Validate the given data type and the template type
+ *
+ * @param[in] data_type data type
+ *
+ * @return true if user provided data type and the template type are conformant
+ */
+ template <typename T>
+ bool validate(DataType data_type);
+
+ /** Get the constant data as a 2d vector of string values
+ *
+ * @return a 2d vector of strings that has the string-converted values
+ */
+ const std::vector<StringVector> &values() const;
+
+ /** Get the underlying data type of the constant values
+ *
+ * @return a @ref ckw::DataType object that represents the underlying data type
+ */
+ DataType data_type() const;
+
+ // Friends
+ friend class KernelWriter;
+
+private:
+ // Data members
+ std::vector<StringVector> _values{};
+ DataType _data_type{};
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_CONSTANTDATA_H
diff --git a/compute_kernel_writer/include/ckw/types/ConvertPolicy.h b/compute_kernel_writer/include/ckw/types/ConvertPolicy.h
new file mode 100644
index 0000000000..43a37ff118
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/ConvertPolicy.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_CONVERTPOLICY_H
+#define CKW_INCLUDE_CKW_TYPES_CONVERTPOLICY_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+enum class ConvertPolicy : int32_t
+{
+ None = 0, // No policy specified.
+ Saturate = 1, // Saturated.
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_CONVERTPOLICY_H
diff --git a/compute_kernel_writer/include/ckw/types/DataType.h b/compute_kernel_writer/include/ckw/types/DataType.h
new file mode 100644
index 0000000000..3447dd61d6
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/DataType.h
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2023 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.
+*/
+
+#ifndef CKW_INCLUDE_CKW_DATATYPE_H
+#define CKW_INCLUDE_CKW_DATATYPE_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** Compute Kernel Writer data types. This data type is used by the code variables and tensor arguments. */
+enum class DataType : int32_t
+{
+ Unknown = 0x00,
+ Fp32 = 0x11,
+ Fp16 = 0x12,
+ Int32 = 0x21,
+ Int16 = 0x22,
+ Int8 = 0x24,
+ Uint32 = 0x31,
+ Uint16 = 0x32,
+ Uint8 = 0x34,
+ Bool = 0x41
+};
+
+} // namespace ckw
+
+#endif //CKW_INCLUDE_CKW_DATATYPE_H
diff --git a/compute_kernel_writer/include/ckw/types/MemoryOperation.h b/compute_kernel_writer/include/ckw/types/MemoryOperation.h
new file mode 100644
index 0000000000..f93f60c51a
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/MemoryOperation.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_MEMORYOPERATION
+#define CKW_INCLUDE_CKW_TYPES_MEMORYOPERATION
+
+namespace ckw
+{
+enum class MemoryOperation
+{
+ Load = 1,
+ Store = 2
+};
+} // namespace ckw
+
+#endif /* CKW_INCLUDE_CKW_TYPES_MEMORYOPERATION */
diff --git a/compute_kernel_writer/include/ckw/types/Operators.h b/compute_kernel_writer/include/ckw/types/Operators.h
new file mode 100644
index 0000000000..77b0519422
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/Operators.h
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2023 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.
+*/
+
+#ifndef CKW_INCLUDE_CKW_TYPES_OPERATORS_H
+#define CKW_INCLUDE_CKW_TYPES_OPERATORS_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** Unary operators and functions. */
+enum class UnaryOp : int32_t
+{
+ LogicalNot = 0x0000, // !
+ BitwiseNot = 0x0001, // ~
+
+ Exp = 0x0010,
+ Tanh = 0x0011,
+ Sqrt = 0x0012,
+ Erf = 0x0013,
+ Fabs = 0x0014,
+ Log = 0x0015,
+ Round = 0x0016,
+ Floor = 0x0017,
+};
+
+/** Assignment operators. */
+enum class AssignmentOp : int32_t
+{
+ Increment = 0x0000, // +=
+ Decrement = 0x0001, // -=
+};
+
+/** Binary operators. */
+enum class BinaryOp : int32_t
+{
+ // Elementwise
+ Add = 0x0000, // +
+ Sub = 0x0001, // -
+ Mul = 0x0002, // *
+ Div = 0x0003, // /
+ Mod = 0x0004, // %
+
+ // Relational
+ Equal = 0x1000, // ==
+ Less = 0x1001, // <
+ LessEqual = 0x1002, // <=
+ Greater = 0x1003, // >
+ GreaterEqual = 0x1004, // >=
+
+ // Algebra
+ MatMul_Nt_Nt = 0x2000, // X
+ MatMul_Nt_T = 0x2001, // X
+ MatMul_T_Nt = 0x2002, // X
+ MatMul_T_T = 0x2003, // X
+ Dot = 0x2004, // .
+
+ // Logical
+ LogicalAnd = 0x3000, // &&
+ LogicalOr = 0x3001, // ||
+
+ // Bitwise
+ BitwiseXOR = 0x4000, // ^
+
+ // Functions
+ Min = 0x8000,
+ Max = 0x8001,
+};
+
+/** Ternary operators. */
+enum class TernaryOp : int32_t
+{
+ Select = 0x0000,
+ Clamp = 0x0001,
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_OPERATORS_H
diff --git a/compute_kernel_writer/include/ckw/types/TargetArchitecture.h b/compute_kernel_writer/include/ckw/types/TargetArchitecture.h
new file mode 100644
index 0000000000..25662a01f0
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/TargetArchitecture.h
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2023 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.
+*/
+
+#ifndef CKW_INCLUDE_CKW_TYPES_TARGETARCHITECTURE_H
+#define CKW_INCLUDE_CKW_TYPES_TARGETARCHITECTURE_H
+
+namespace ckw
+{
+
+/** Target platform architecture. */
+enum class TargetArchitecture
+{
+ Unknown,
+ GpuArmMaliValhall,
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_TARGETARCHITECTURE_H
diff --git a/compute_kernel_writer/include/ckw/types/TargetLanguage.h b/compute_kernel_writer/include/ckw/types/TargetLanguage.h
new file mode 100644
index 0000000000..1f507573dd
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/TargetLanguage.h
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2023 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.
+*/
+
+#ifndef CKW_INCLUDE_CKW_TYPES_TARGETLANGUAGE_H
+#define CKW_INCLUDE_CKW_TYPES_TARGETLANGUAGE_H
+
+namespace ckw
+{
+
+/** Target language. */
+enum class TargetLanguage
+{
+ Unknown,
+ OpenCL
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_TARGETLANGUAGE_H
diff --git a/compute_kernel_writer/include/ckw/types/TensorComponentType.h b/compute_kernel_writer/include/ckw/types/TensorComponentType.h
new file mode 100644
index 0000000000..7a5031d8c0
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/TensorComponentType.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_TENSORCOMPONENTTYPE_H
+#define CKW_INCLUDE_CKW_TYPES_TENSORCOMPONENTTYPE_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** Compute Kernel Writer tensor component.
+ *
+ * The tensor components are used to access specific backend-agnostic tensor arguments,
+ * such as the tensor dimensions and tensor strides.
+ * The tensor component is represented as an unsigned integer. The value of the integer value
+ * is assigned to retrieve the information through the @ref TensorComponentBitmask.
+ */
+enum class TensorComponentType : uint32_t
+{
+ Unknown = 0x00000000,
+ OffsetFirstElement = 0x01000000,
+ Stride0 = 0x02000001,
+ Stride1 = 0x02000002,
+ Stride2 = 0x02000003,
+ Stride3 = 0x02000004,
+ Stride4 = 0x02000005,
+ Dim0 = 0x04000001,
+ Dim1 = 0x04000002,
+ Dim2 = 0x04000003,
+ Dim3 = 0x04000004,
+ Dim4 = 0x04000005,
+ Dim1xDim2 = 0x08000032,
+ Dim2xDim3 = 0x08000043,
+ Dim1xDim2xDim3 = 0x08000432
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_TENSORCOMPONENTTYPE_H
diff --git a/compute_kernel_writer/include/ckw/types/TensorDataLayout.h b/compute_kernel_writer/include/ckw/types/TensorDataLayout.h
new file mode 100644
index 0000000000..532b299910
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/TensorDataLayout.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_TENSORDATALAYOUT_H
+#define CKW_INCLUDE_CKW_TYPES_TENSORDATALAYOUT_H
+
+namespace ckw
+{
+
+/** Compute Kernel Writer tensor data layout (or memory format) */
+enum class TensorDataLayout
+{
+ Unknown,
+ Nhwc,
+ Ndhwc
+};
+
+/** Compute Kernel Writer tensor data layout component */
+enum class TensorDataLayoutComponent
+{
+ Unknown,
+ N,
+ D,
+ H,
+ W,
+ C,
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_TENSORDATALAYOUT_H
diff --git a/compute_kernel_writer/include/ckw/types/TensorSamplerTypes.h b/compute_kernel_writer/include/ckw/types/TensorSamplerTypes.h
new file mode 100644
index 0000000000..512d0b4501
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/TensorSamplerTypes.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_TENSORSAMPLERTYPES_H
+#define CKW_INCLUDE_CKW_TYPES_TENSORSAMPLERTYPES_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+// This enum class defines how the dimensions of a 3d tensor is mapped into x,y and z coordianates.
+enum class TensorSamplerFormat : int32_t
+{
+ Unknown = 0,
+ Dim0_Dim1xDim2_1 = 1, // Original dimensions 1 and 2 are collapsed onto y-axis
+ Dim0_Dim1_Dim2 = 2 // Original dimensions stays as they're defined. No collapsing.
+};
+
+/** Tensor sampler address mode enum class for X dimension
+ *
+ * The following address modes are available in total:
+ * Unknown
+ * None : The user guarantees that the coordinate is always in-bound
+ * OverlappingMin : (FIXED shapes only) Reduce the load/store length when x == 0 (MIN). The load length will be width % original length
+ * Leftover elements can be handled using overlapping. This involves processing some of the elements in the array twice.
+ * ClampToBorderMaxOnly : Clamp to max value allowed in the corresponding dimension, and construct an if/else guard to prevent out of bound access,
+ * e.g. if( y < size-of-dimension-y ){ <do the operation> }
+ * SkipLessThanZero : Skip loading/storing if the index is less than 0
+ *
+ * Individual dimensions choose which adddress mode to implement in their respective enum classes.
+ */
+enum class TensorSamplerAddressModeX : int32_t
+{
+ Unknown = 0,
+ None = 1,
+ OverlappingMin = 2
+};
+
+/**
+ * Similar to @ref TensorSamplerAddressModeX
+ */
+enum class TensorSamplerAddressModeY : int32_t
+{
+ Unknown = 0,
+ None = 1,
+ OverlappingMin = 2,
+ ClampToBorderMaxOnly = 3,
+ SkipLessThanZero = 4
+};
+
+/**
+ * Similar to @ref TensorSamplerAddressModeX
+ */
+enum class TensorSamplerAddressModeZ : int32_t
+{
+ Unknown = 0,
+ None = 1,
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_TENSORSAMPLERTYPES_H
diff --git a/compute_kernel_writer/include/ckw/types/TensorStorageType.h b/compute_kernel_writer/include/ckw/types/TensorStorageType.h
new file mode 100644
index 0000000000..5a2f17d520
--- /dev/null
+++ b/compute_kernel_writer/include/ckw/types/TensorStorageType.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_INCLUDE_CKW_TYPES_TENSORSTORAGETYPE_H
+#define CKW_INCLUDE_CKW_TYPES_TENSORSTORAGETYPE_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** Compute Kernel Writer tensor storage.
+ * The tensor storage represents the type of tensor memory object.
+ */
+enum class TensorStorageType : uint32_t
+{
+ Unknown = 0x00000000,
+ BufferUint8Ptr = 0x01000000,
+ Texture2dReadOnly = 0x02000001,
+ Texture2dWriteOnly = 0x02000010,
+};
+
+} // namespace ckw
+
+#endif // CKW_INCLUDE_CKW_TYPES_TENSORSTORAGETYPE_H
diff --git a/compute_kernel_writer/src/Error.cpp b/compute_kernel_writer/src/Error.cpp
new file mode 100644
index 0000000000..e1e4bffcec
--- /dev/null
+++ b/compute_kernel_writer/src/Error.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2023 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 "ckw/Error.h"
+
+#include <string>
+
+namespace ckw
+{
+std::string
+create_error_msg(const std::string &file, const std::string &func, const std::string &line, const std::string &msg)
+{
+ std::string err;
+ err += "[COMPUTE_KERNEL_WRITER][ERROR]:";
+ err += " " + file + ":" + line;
+ err += " " + func;
+ err += " " + msg;
+ return err;
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/Helpers.cpp b/compute_kernel_writer/src/Helpers.cpp
new file mode 100644
index 0000000000..82d4c4e917
--- /dev/null
+++ b/compute_kernel_writer/src/Helpers.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023 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 "src/Helpers.h"
+
+#include "ckw/Error.h"
+
+namespace ckw
+{
+std::string dec_to_hex_as_string(int32_t dec)
+{
+ switch (dec)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ return std::to_string(dec);
+ case 10:
+ return "A";
+ case 11:
+ return "B";
+ case 12:
+ return "C";
+ case 13:
+ return "D";
+ case 14:
+ return "E";
+ case 15:
+ return "F";
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported decimal number");
+ return "";
+ }
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/Helpers.h b/compute_kernel_writer/src/Helpers.h
new file mode 100644
index 0000000000..16c06d60e7
--- /dev/null
+++ b/compute_kernel_writer/src/Helpers.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef COMPUTE_KERNEL_WRITER_SRC_HELPERS_H
+#define COMPUTE_KERNEL_WRITER_SRC_HELPERS_H
+
+#include <cstdint>
+#include <string>
+
+/** Generic helper functions */
+namespace ckw
+{
+/** Helper function to convert a decimal number passed as int32_t variable to hexadecimal number as string
+ *
+ * @param[in] dec Decimal number. It must be >= 0 and < 16
+ *
+ * @return the OpenCL datatype as a string
+ */
+std::string dec_to_hex_as_string(int32_t dec);
+
+/** Helper function to clamp a value between min_val and max_val
+ *
+ * @param[in] val Value to clamp
+ * @param[in] min_val Lower value
+ * @param[in] max_val Upper value
+ *
+ * @return the clamped value
+ */
+template <typename T>
+T clamp(const T &val, const T &min_val, const T &max_val)
+{
+ return std::max(min_val, std::min(val, max_val));
+}
+} // namespace ckw
+#endif /* COMPUTE_KERNEL_WRITER_SRC_HELPERS_H */
diff --git a/compute_kernel_writer/src/ITensor.h b/compute_kernel_writer/src/ITensor.h
new file mode 100644
index 0000000000..4c1c56fd35
--- /dev/null
+++ b/compute_kernel_writer/src/ITensor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_ITENSOR_H
+#define CKW_SRC_ITENSOR_H
+
+#include "src/ITensorArgument.h"
+
+namespace ckw
+{
+
+/** The generic class for all tensor objects in CKW.
+ *
+ * Tensors in CKW are always kernel arguments consisting of:
+ * - Essential information such as name, tensor info, etc.
+ * - Tensor storage access: allowing load/store operation to perform.
+ * - Tensor component access: allowing interaction with tensor information such as shape, strides, etc. in the form of tile objects.
+ */
+class ITensor : public ITensorArgument, public ITensorStorageAccess, public ITensorComponentAccess
+{
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_ITENSOR_H \ No newline at end of file
diff --git a/compute_kernel_writer/src/ITensorArgument.h b/compute_kernel_writer/src/ITensorArgument.h
new file mode 100644
index 0000000000..ece45a4dc4
--- /dev/null
+++ b/compute_kernel_writer/src/ITensorArgument.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_ITENSORARGUMENT_H
+#define CKW_SRC_ITENSORARGUMENT_H
+
+#include "ckw/TensorInfo.h"
+#include "ckw/types/TensorComponentType.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include "src/ITile.h"
+
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+
+class ITensorComponent;
+
+/** Tensor storage variable */
+struct TensorStorageVariable
+{
+ std::string val{""}; /** Tensor storage as a string */
+ TensorStorageType type{TensorStorageType::Unknown}; /** Tensor storage type */
+};
+
+/** Tensor argument base class.
+ * A tensor is a multidimensional array used to store data. To access an element (or multiple elements) from a tensor,
+ * the following information are required:
+ * -# The data memory object. For example, the pointer to the array
+ * -# The tensor components, such as the size of each tensor dimension, or the number of elements in bytes contained in each dimension (also known as the "stride")
+ */
+class ITensorArgument
+{
+public:
+ virtual ~ITensorArgument() = default;
+ /** Method to get the name of the tensor argument.
+ *
+ * @return the name of the tensor argument
+ */
+ std::string name() const
+ {
+ return _basename;
+ }
+
+ /** Method to get the tensor info
+ *
+ * @return the @ref TensorInfo
+ */
+ TensorInfo &info()
+ {
+ return _info;
+ }
+
+ /** Method to get the tensor info
+ *
+ * @return the @ref TensorInfo
+ */
+ const TensorInfo &info() const
+ {
+ return _info;
+ }
+
+protected:
+ TensorInfo _info{}; // Tensor info
+ std::string _basename{""}; // Tensor name
+};
+
+/** Tensor component argument base class */
+class ITensorComponentAccess
+{
+public:
+ virtual ~ITensorComponentAccess() = default;
+ /** Method to get the tensor component variable as a tile.
+ *
+ * @param[in] x The tensor component to query
+ *
+ * @return the tensor component variable as a @ref ITile.
+ */
+ virtual ITile &component(TensorComponentType x) = 0;
+ /** Method to get all tensor components needed to access the data in the tensor
+ *
+ * The tensor components returned by this method must be all passed as kernel argument
+ *
+ * @return a vector containing all the tensor components as pointers to @ref ITensorComponent objects.
+ */
+ virtual std::vector<const ITensorComponent *> components() const = 0;
+};
+
+/** Tensor storage argument base class */
+class ITensorStorageAccess
+{
+public:
+ virtual ~ITensorStorageAccess() = default;
+ /** Method to get the tensor storage as a string
+ *
+ * @param[in] x The tensor storage to query
+ *
+ * @return the tensor storage as a @ref TensorStorageVariable
+ */
+ virtual TensorStorageVariable &storage(TensorStorageType x) = 0;
+ /** Method to get all tensor storages needed to access the data in the tensor
+ *
+ * The tensor storages returned by this method must be all passed as kernel argument
+ *
+ * @return a vector containing all the tensor storages as @ref TensorStorageVariable objects
+ */
+ virtual std::vector<TensorStorageVariable> storages() const = 0;
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_ITENSORARGUMENT_H
diff --git a/compute_kernel_writer/src/ITensorComponent.h b/compute_kernel_writer/src/ITensorComponent.h
new file mode 100644
index 0000000000..f9c9d8fd81
--- /dev/null
+++ b/compute_kernel_writer/src/ITensorComponent.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_ITENSORCOMPONENT_H
+#define CKW_SRC_ITENSORCOMPONENT_H
+
+#include "ckw/types/TensorComponentType.h"
+
+#include "src/ITile.h"
+
+namespace ckw
+{
+
+/** A tensor component provides access to tensor information such as shape, strides, etc. in the form of @ref ITile objects. */
+class ITensorComponent
+{
+public:
+ /** Destructor. */
+ virtual ~ITensorComponent() = default;
+
+ /** Get the tile variable for the component. */
+ virtual ITile &tile() = 0;
+
+ /** Get the const tile variable for the component. */
+ virtual const ITile &tile() const = 0;
+
+ /** Get the component type. */
+ virtual TensorComponentType component_type() const = 0;
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_ITENSORCOMPONENT_H
diff --git a/compute_kernel_writer/src/ITile.cpp b/compute_kernel_writer/src/ITile.cpp
new file mode 100644
index 0000000000..eeb7816068
--- /dev/null
+++ b/compute_kernel_writer/src/ITile.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023 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 "src/ITile.h"
+
+namespace ckw
+{
+
+bool ITile::is_scalar() const
+{
+ return info().width() == 1 && info().height() == 1;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/ITile.h b/compute_kernel_writer/src/ITile.h
new file mode 100644
index 0000000000..8eaac5ac12
--- /dev/null
+++ b/compute_kernel_writer/src/ITile.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef CKW_SRC_ITILE_H
+#define CKW_SRC_ITILE_H
+
+#include "ckw/TileInfo.h"
+
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+/** Compute Kernel Writer tile container. It contains the variables stored in the tile as a string */
+using TileContainer = std::vector<std::vector<std::string>>;
+
+/** Tile descriptor which reports the underlying datatype and vector length */
+struct TileVariableDescriptor
+{
+ DataType dt{DataType::Unknown}; /** Data type */
+ int32_t len{1}; /** Number of elements in a single variable. For example, 1 for scalar */
+};
+
+/** Tile variable */
+struct TileVariable
+{
+ std::string str{""}; /** Tile variable as a string */
+ TileVariableDescriptor desc{}; /** Tile value descriptor which reports the datatype and vector length */
+};
+
+/** Interface to provide support for scalar access for a Tile.
+ */
+class IScalarAccess
+{
+public:
+ virtual ~IScalarAccess() = default;
+
+ /** Method to get the scalar variable from a tile as a string
+ * @param[in] row Tile row. If out-of-bound, the row is clamped to the nearest valid edge
+ * @param[in] col Tile column. If out-of-bound, the column is clamped to the nearest valid edge
+ *
+ * @return the @ref TileVariable
+ */
+ virtual TileVariable scalar(int32_t row, int32_t col) const = 0;
+};
+
+/** Interface to provide support for vector access for a tile.
+ */
+class IVectorAccess
+{
+public:
+ virtual ~IVectorAccess() = default;
+
+ /** Method to get the vector variable from a tile.
+ * The user can query the list of supported vector lengths through the supported_vector_lengths() method.
+ *
+ * @param[in] row Tile row. If out-of-bound, the row is clamped to the nearest valid edge
+ *
+ * @return the vector variable as a @ref TileVariable
+ */
+ virtual TileVariable vector(int32_t row) const = 0;
+
+ /** Method to get a sub-vector variable. The length of the sub-vector must be supported by the derived IVectorAccess class
+ *
+ * @param[in] row Tile row. If out-of-bound, the row is clamped to the nearest valid edge
+ * @param[in] col_start Tile starting column to get the sub-vector. If out-of-bound, the derived IVectorAccess class may throw an assert.
+ * @param[in] width The width of the sub-vector. The width must be supported by the derived IVectorAccess class and the last element must be in-bound.
+ *
+ * @return the vector variable as a @ref TileVariable
+ */
+ virtual TileVariable vector(int32_t row, int32_t col_start, int32_t width) const = 0;
+
+ /** Method to get the supported vector length.
+ *
+ * @return a vector containing the supported vector lengths
+ */
+ virtual std::vector<int32_t> supported_vector_lengths() const = 0;
+};
+
+/** Tile base class.
+ * A Tile is a collection of variables (either program variables or constants) used to express a 2D data.
+ */
+class ITile : public IScalarAccess
+{
+public:
+ virtual ~ITile() = default;
+
+ /** Method to get all TileVariable objects
+ *
+ * @return a vector containing all @ref TileVariable objects
+ */
+ virtual std::vector<TileVariable> all() const = 0;
+
+ /** Method to get the name of the tile.
+ *
+ * @return the name of the tile
+ */
+ virtual const std::string &name() const = 0;
+
+ /** Method to get the tile info
+ *
+ * @return the @ref TileInfo
+ */
+ virtual const TileInfo &info() const = 0;
+
+ /** Method to know whether the tile is assignable or not.
+ * For example, a constant tile is not assignable.
+ *
+ * @return true if the tile is assignable
+ */
+ virtual bool is_assignable() const = 0;
+
+ /** Get whether the tile is scalar, i.e. the width and height are both 1.
+ *
+ * @return true if the tile is scalar.
+ */
+ bool is_scalar() const;
+};
+} // namespace ckw
+
+#endif // CKW_SRC_ITILE_H
diff --git a/compute_kernel_writer/src/Kernel.cpp b/compute_kernel_writer/src/Kernel.cpp
new file mode 100644
index 0000000000..12389b3816
--- /dev/null
+++ b/compute_kernel_writer/src/Kernel.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2023 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 "ckw/Kernel.h"
+
+#include "ckw/types/TargetLanguage.h"
+
+namespace ckw
+{
+
+Kernel::~Kernel() = default;
+
+Kernel::Kernel(TargetLanguage language, const std::vector<KernelArgument> &arguments, const std::string &source_code)
+ : _language(language), _arguments(arguments), _source_code(source_code)
+{
+}
+
+TargetLanguage Kernel::target_language() const
+{
+ return _language;
+}
+
+const std::vector<KernelArgument> &Kernel::arguments() const
+{
+ return _arguments;
+}
+
+const std::string &Kernel::source_code() const
+{
+ return _source_code;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/KernelArgument.cpp b/compute_kernel_writer/src/KernelArgument.cpp
new file mode 100644
index 0000000000..a640d36507
--- /dev/null
+++ b/compute_kernel_writer/src/KernelArgument.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2023 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 "ckw/KernelArgument.h"
+
+#include "ckw/Error.h"
+
+namespace ckw
+{
+
+KernelArgument::KernelArgument(int32_t tensor_id, TensorStorageType storage_type)
+ : _type(Type::TensorStorage), _id(tensor_id)
+{
+ _sub_id.tensor_storage_type = storage_type;
+}
+
+KernelArgument::KernelArgument(int32_t tensor_id, TensorComponentType component_type)
+ : _type(Type::TensorComponent), _id(tensor_id)
+{
+ _sub_id.tensor_component_type = component_type;
+}
+
+KernelArgument::Type KernelArgument::type() const
+{
+ return _type;
+}
+
+int32_t KernelArgument::id() const
+{
+ return _id;
+}
+
+TensorStorageType KernelArgument::tensor_storage_type() const
+{
+ CKW_ASSERT(_type == Type::TensorStorage);
+
+ return _sub_id.tensor_storage_type;
+}
+
+TensorComponentType KernelArgument::tensor_component_type() const
+{
+ CKW_ASSERT(_type == Type::TensorComponent);
+
+ return _sub_id.tensor_component_type;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/KernelWriter.cpp b/compute_kernel_writer/src/KernelWriter.cpp
new file mode 100644
index 0000000000..92a36746ce
--- /dev/null
+++ b/compute_kernel_writer/src/KernelWriter.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2023 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 "ckw/KernelWriter.h"
+
+#include "ckw/Error.h"
+#include "ckw/TileOperand.h"
+#include "ckw/types/TargetArchitecture.h"
+#include "ckw/types/TargetLanguage.h"
+
+#include "src/cl/CLKernelWriter.h"
+#include "src/cl/CLTensorArgument.h"
+#include "src/cl/CLTile.h"
+#include "src/TileView.h"
+
+#include <tuple>
+
+namespace ckw
+{
+
+KernelWriter::~KernelWriter() = default;
+
+std::unique_ptr<KernelWriter> KernelWriter::create_instance(TargetArchitecture architecture, TargetLanguage language)
+{
+ CKW_UNUSED(architecture);
+ switch (language)
+ {
+ case TargetLanguage::OpenCL:
+ // Currently this is the oldest and the only supported GPU architecture.
+ CKW_ASSERT(architecture == TargetArchitecture::GpuArmMaliValhall);
+ return std::make_unique<CLKernelWriter>();
+
+ default:
+ CKW_THROW_MSG("Language not supported!");
+ }
+}
+
+int32_t KernelWriter::new_id_space()
+{
+ _id_space = ++_last_created_id_space;
+
+ return _id_space;
+}
+
+int32_t KernelWriter::id_space() const
+{
+ return _id_space;
+}
+
+KernelWriter &KernelWriter::id_space(int32_t value)
+{
+ CKW_ASSERT(value <= _last_created_id_space);
+
+ _id_space = value;
+
+ return *this;
+}
+
+void KernelWriter::write_body(const std::function<void()> &body)
+{
+ const auto curr_id_space = id_space();
+ new_id_space();
+ body();
+ id_space(curr_id_space);
+}
+
+std::string KernelWriter::generate_full_name(const std::string &name) const
+{
+ return "G" + std::to_string(id_space()) + "__" + name;
+}
+
+TileOperand KernelWriter::create_tile_operand(ITile &tile)
+{
+ return TileOperand(tile);
+}
+
+std::tuple<ITile &, TileArea> KernelWriter::get_tile(const TileOperand &operand)
+{
+ return {*operand._tile, {operand._row_start, operand._row_end, operand._col_start, operand._col_end}};
+}
+
+TensorOperand KernelWriter::create_tensor_operand(ITensor &tensor)
+{
+ return TensorOperand(tensor);
+}
+
+ITensor &KernelWriter::get_tensor(const TensorOperand &operand)
+{
+ CKW_ASSERT(operand._tensor != nullptr);
+ return *operand._tensor;
+}
+
+const std::vector<std::vector<std::string>> &KernelWriter::get_values(const ConstantData &data)
+{
+ return data.values();
+}
+
+DataType KernelWriter::get_data_type(const ConstantData &data)
+{
+ return data.data_type();
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/Tensor3dMapper.cpp b/compute_kernel_writer/src/Tensor3dMapper.cpp
new file mode 100644
index 0000000000..acef6412a4
--- /dev/null
+++ b/compute_kernel_writer/src/Tensor3dMapper.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2023 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 "Tensor3dMapper.h"
+
+#include "ckw/Error.h"
+#include "ckw/types/TensorSamplerTypes.h"
+
+#include "src/ITensor.h"
+#include "src/ITile.h"
+
+namespace ckw
+{
+Tensor3dMapper::Tensor3dMapper(ITensor *tensor, TensorSamplerFormat format) : _tensor(tensor), _format(format)
+{
+}
+
+TileVariable Tensor3dMapper::dim_x() const
+{
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Dim0).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::dim_y() const
+{
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ return _tensor->component(TensorComponentType::Dim1xDim2).scalar(0, 0);
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Dim1).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::dim_z() const
+{
+ TileVariable dim_one;
+
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ dim_one = _tensor->component(TensorComponentType::Dim3).scalar(0, 0);
+ dim_one.str = "1";
+ return dim_one;
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Dim2).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::dim_batch() const
+{
+ TileVariable dim_one;
+
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Dim3).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::stride_x() const
+{
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Stride0).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::stride_y() const
+{
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Stride1).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::stride_z() const
+{
+ TileVariable stride_zero;
+
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ stride_zero = _tensor->component(TensorComponentType::Stride3).scalar(0, 0);
+ stride_zero.str = "0";
+ return stride_zero;
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Stride2).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+
+TileVariable Tensor3dMapper::stride_batch() const
+{
+ switch (_format)
+ {
+ case TensorSamplerFormat::Dim0_Dim1xDim2_1:
+ case TensorSamplerFormat::Dim0_Dim1_Dim2:
+ return _tensor->component(TensorComponentType::Stride3).scalar(0, 0);
+ default:
+ CKW_THROW_MSG("Unsupported tensor format");
+ return _tensor->component(TensorComponentType::Unknown).scalar(0, 0);
+ }
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/Tensor3dMapper.h b/compute_kernel_writer/src/Tensor3dMapper.h
new file mode 100644
index 0000000000..e94b595193
--- /dev/null
+++ b/compute_kernel_writer/src/Tensor3dMapper.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_TENSOR3DMAPPER_H
+#define CKW_SRC_TENSOR3DMAPPER_H
+
+#include <string>
+
+namespace ckw
+{
+// Forward declarations
+class ITensor;
+enum class TensorSamplerFormat;
+struct TileVariable;
+
+/** This internal-only class is responsible to map an Nd tensor spatial dimensions to a 3d tensor spatial dimensions with the
+ * help of TensorSamplerFormat.
+ * Attention: The batch is not considered as a spatial dimension and it is treated as an offset
+ *
+ * The aim of the dimensionality reduction is primarily to reduce
+ * the address calculation to:
+ * x + y * stride_y + z * stride_z + offset, where offset is determined by the batch (for example, b * stride_batch).
+ *
+ */
+class Tensor3dMapper
+{
+public:
+ /** Constructor */
+ Tensor3dMapper(ITensor *tensor, TensorSamplerFormat format);
+
+ /** Get dimension x as string */
+ TileVariable dim_x() const;
+
+ /** Get dimension y as string */
+ TileVariable dim_y() const;
+
+ /** Get dimension z as string */
+ TileVariable dim_z() const;
+
+ /** Get batch dimension as string */
+ TileVariable dim_batch() const;
+
+ /** Get stride for dimension x as string */
+ TileVariable stride_x() const;
+
+ /** Get stride for dimension y as string */
+ TileVariable stride_y() const;
+
+ /** Get stride for dimension z as string */
+ TileVariable stride_z() const;
+
+ /** Get stride for batch dimension as string */
+ TileVariable stride_batch() const;
+
+private:
+ ITensor *_tensor;
+ TensorSamplerFormat _format;
+};
+} // namespace ckw
+
+#endif /* CKW_SRC_TENSOR3DMAPPER_H */
diff --git a/compute_kernel_writer/src/TensorInfo.cpp b/compute_kernel_writer/src/TensorInfo.cpp
new file mode 100644
index 0000000000..561c126469
--- /dev/null
+++ b/compute_kernel_writer/src/TensorInfo.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2023 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 "ckw/TensorInfo.h"
+
+namespace ckw
+{
+TensorInfo::TensorInfo(DataType dt, const TensorShape &shape, TensorDataLayout dl, int32_t id)
+ : _shape(shape), _dt(dt), _dl(dl), _id(id)
+{
+}
+
+TensorInfo &TensorInfo::shape(const TensorShape &shape)
+{
+ _shape = shape;
+ return *this;
+}
+
+TensorShape TensorInfo::shape() const
+{
+ return _shape;
+}
+
+TensorInfo &TensorInfo::data_type(DataType dt)
+{
+ _dt = dt;
+ return *this;
+}
+
+DataType TensorInfo::data_type() const
+{
+ return _dt;
+}
+
+TensorInfo &TensorInfo::data_layout(TensorDataLayout dl)
+{
+ _dl = dl;
+ return *this;
+}
+
+TensorDataLayout TensorInfo::data_layout() const
+{
+ return _dl;
+}
+
+TensorInfo &TensorInfo::id(int32_t id)
+{
+ _id = id;
+ return *this;
+}
+
+int32_t TensorInfo::id() const
+{
+ return _id;
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TensorOperand.cpp b/compute_kernel_writer/src/TensorOperand.cpp
new file mode 100644
index 0000000000..94997537d8
--- /dev/null
+++ b/compute_kernel_writer/src/TensorOperand.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2023 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 "ckw/TensorOperand.h"
+
+#include "ckw/Error.h"
+
+#include "src/ITensor.h"
+
+namespace ckw
+{
+
+TensorOperand::TensorOperand() : _tensor(nullptr)
+{
+}
+
+TensorOperand::TensorOperand(ITensor &tensor) : _tensor(&tensor)
+{
+}
+
+bool TensorOperand::is_valid() const
+{
+ return _tensor != nullptr;
+}
+
+const TensorInfo &TensorOperand::info() const
+{
+ CKW_ASSERT(is_valid() == true);
+ return _tensor->info();
+}
+
+TileOperand TensorOperand::stride0()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Stride0));
+}
+
+TileOperand TensorOperand::stride1()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Stride1));
+}
+
+TileOperand TensorOperand::stride2()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Stride2));
+}
+
+TileOperand TensorOperand::stride3()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Stride3));
+}
+
+TileOperand TensorOperand::stride4()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Stride4));
+}
+
+TileOperand TensorOperand::dim0()
+{
+ return TileOperand(_tensor->component(TensorComponentType::Dim0));
+}
+
+TileOperand TensorOperand::dim1()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim1));
+}
+
+TileOperand TensorOperand::dim2()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim2));
+}
+
+TileOperand TensorOperand::dim3()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim3));
+}
+
+TileOperand TensorOperand::dim4()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim4));
+}
+
+TileOperand TensorOperand::dim1_dim2()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim1xDim2));
+}
+
+TileOperand TensorOperand::dim1_dim2_dim3()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim1xDim2xDim3));
+}
+
+TileOperand TensorOperand::dim2_dim3()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::Dim2xDim3));
+}
+
+TileOperand TensorOperand::offset_first_element_in_bytes()
+{
+ CKW_ASSERT(is_valid() == true);
+ return TileOperand(_tensor->component(TensorComponentType::OffsetFirstElement));
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TensorSampler.cpp b/compute_kernel_writer/src/TensorSampler.cpp
new file mode 100644
index 0000000000..e81c5f9d66
--- /dev/null
+++ b/compute_kernel_writer/src/TensorSampler.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2023 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 "ckw/TensorSampler.h"
+
+namespace ckw
+{
+
+TensorSampler::TensorSampler() = default;
+
+TensorSampler::TensorSampler(TensorStorageType storage,
+ TensorSamplerFormat format,
+ TensorSamplerAddressModeX address_mode_x,
+ TensorSamplerAddressModeY address_mode_y,
+ TensorSamplerAddressModeZ address_mode_z)
+ : _storage(storage),
+ _format(format),
+ _address_mode_x(address_mode_x),
+ _address_mode_y(address_mode_y),
+ _address_mode_z(address_mode_z)
+{
+}
+
+TensorStorageType TensorSampler::storage() const
+{
+ return _storage;
+}
+
+TensorSampler &TensorSampler::storage(TensorStorageType storage)
+{
+ _storage = storage;
+ return *this;
+}
+
+/** Get the format of the tensor. */
+TensorSamplerFormat TensorSampler::format() const
+{
+ return _format;
+}
+
+/** Set the format of the tensor. */
+TensorSampler &TensorSampler::format(TensorSamplerFormat format)
+{
+ _format = format;
+ return *this;
+}
+
+/** Get the address mode of the x dimension. */
+TensorSamplerAddressModeX TensorSampler::address_mode_x() const
+{
+ return _address_mode_x;
+}
+
+/** Set the address mode of the x-dimension. */
+TensorSampler &TensorSampler::address_mode_x(TensorSamplerAddressModeX address_mode_x)
+{
+ _address_mode_x = address_mode_x;
+ return *this;
+}
+
+/** Get the address mode of the y dimension. */
+TensorSamplerAddressModeY TensorSampler::address_mode_y() const
+{
+ return _address_mode_y;
+}
+
+/** Set the address mode of the y dimension. */
+TensorSampler &TensorSampler::address_mode_y(TensorSamplerAddressModeY address_mode_y)
+{
+ _address_mode_y = address_mode_y;
+ return *this;
+}
+
+/** Get the address mode of the z dimension. */
+TensorSamplerAddressModeZ TensorSampler::address_mode_z() const
+{
+ return _address_mode_z;
+}
+
+/** Set the address mode of the z dimension. */
+TensorSampler &TensorSampler::address_mode_z(TensorSamplerAddressModeZ address_mode_z)
+{
+ _address_mode_z = address_mode_z;
+ return *this;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TensorUtils.cpp b/compute_kernel_writer/src/TensorUtils.cpp
new file mode 100644
index 0000000000..17fc9547ae
--- /dev/null
+++ b/compute_kernel_writer/src/TensorUtils.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2023 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 "src/TensorUtils.h"
+
+#include "ckw/Error.h"
+#include "ckw/TensorInfo.h"
+#include "ckw/types/TensorComponentType.h"
+
+namespace ckw
+{
+TensorComponentType get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutComponent component)
+{
+ switch (layout)
+ {
+ case TensorDataLayout::Nhwc:
+ switch (component)
+ {
+ case TensorDataLayoutComponent::C:
+ return TensorComponentType::Dim0;
+ case TensorDataLayoutComponent::W:
+ return TensorComponentType::Dim1;
+ case TensorDataLayoutComponent::H:
+ return TensorComponentType::Dim2;
+ case TensorDataLayoutComponent::N:
+ return TensorComponentType::Dim3;
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NHWC");
+ return TensorComponentType::Unknown;
+ }
+ case TensorDataLayout::Ndhwc:
+ switch (component)
+ {
+ case TensorDataLayoutComponent::C:
+ return TensorComponentType::Dim0;
+ case TensorDataLayoutComponent::W:
+ return TensorComponentType::Dim1;
+ case TensorDataLayoutComponent::H:
+ return TensorComponentType::Dim2;
+ case TensorDataLayoutComponent::D:
+ return TensorComponentType::Dim3;
+ case TensorDataLayoutComponent::N:
+ return TensorComponentType::Dim4;
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NDHWC");
+ return TensorComponentType::Unknown;
+ }
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor data layout");
+ return TensorComponentType::Unknown;
+ }
+}
+
+TensorComponentType get_tensor_stride(TensorDataLayout layout, TensorDataLayoutComponent component)
+{
+ switch (layout)
+ {
+ case TensorDataLayout::Nhwc:
+ switch (component)
+ {
+ case TensorDataLayoutComponent::C:
+ return TensorComponentType::Stride0;
+ case TensorDataLayoutComponent::W:
+ return TensorComponentType::Stride1;
+ case TensorDataLayoutComponent::H:
+ return TensorComponentType::Stride2;
+ case TensorDataLayoutComponent::N:
+ return TensorComponentType::Stride3;
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NHWC");
+ return TensorComponentType::Unknown;
+ }
+ case TensorDataLayout::Ndhwc:
+ switch (component)
+ {
+ case TensorDataLayoutComponent::C:
+ return TensorComponentType::Stride0;
+ case TensorDataLayoutComponent::W:
+ return TensorComponentType::Stride1;
+ case TensorDataLayoutComponent::H:
+ return TensorComponentType::Stride2;
+ case TensorDataLayoutComponent::D:
+ return TensorComponentType::Stride3;
+ case TensorDataLayoutComponent::N:
+ return TensorComponentType::Stride4;
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor component for NDHWC");
+ return TensorComponentType::Unknown;
+ }
+ default:
+ COMPUTE_KERNEL_WRITER_ERROR_ON_MSG("Unsupported tensor data layout");
+ return TensorComponentType::Unknown;
+ }
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TensorUtils.h b/compute_kernel_writer/src/TensorUtils.h
new file mode 100644
index 0000000000..bb0af5c0b9
--- /dev/null
+++ b/compute_kernel_writer/src/TensorUtils.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_TENSORUTILS_H
+#define CKW_SRC_TENSORUTILS_H
+
+#include <cstdint>
+
+/** Tensor specific utility functions */
+namespace ckw
+{
+// Forward declarations
+enum class TensorDataLayout;
+enum class TensorDataLayoutComponent;
+enum class TensorComponentType : uint32_t;
+
+/** Get tensor dimension from a given data layout and data layout component
+ *
+ * @param[in] layout Layout of the tensor
+ * @param[in] component Data layout component
+ *
+ * @return the @ref TensorComponent
+ */
+TensorComponentType get_tensor_dimension(TensorDataLayout layout, TensorDataLayoutComponent component);
+
+/** Get tensor stride from a given data layout and data layout component
+ *
+ * @param[in] layout Layout of the tensor
+ * @param[in] component Data layout component
+ *
+ * @return the @ref TensorComponent
+ */
+TensorComponentType get_tensor_stride(TensorDataLayout layout, TensorDataLayoutComponent component);
+} // namespace ckw
+
+#endif // CKW_SRC_TENSORUTILS_H
diff --git a/compute_kernel_writer/src/TileInfo.cpp b/compute_kernel_writer/src/TileInfo.cpp
new file mode 100644
index 0000000000..273266eedc
--- /dev/null
+++ b/compute_kernel_writer/src/TileInfo.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2023 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 "ckw/TileInfo.h"
+
+namespace ckw
+{
+TileInfo::TileInfo(DataType dt) : _dt(dt), _shape({{1, 1}})
+{
+}
+
+TileInfo::TileInfo(DataType dt, int32_t w) : _dt(dt), _shape({{w, 1}})
+{
+}
+
+TileInfo::TileInfo(DataType dt, int32_t h, int32_t w) : _dt(dt), _shape({{w, h}})
+{
+}
+
+TileInfo &TileInfo::width(int32_t w)
+{
+ _shape[kTileWidthIdx] = w;
+ return *this;
+}
+
+int32_t TileInfo::width() const
+{
+ return _shape[kTileWidthIdx];
+}
+
+TileInfo &TileInfo::height(int32_t h)
+{
+ _shape[kTileHeightIdx] = h;
+ return *this;
+}
+
+int32_t TileInfo::height() const
+{
+ return _shape[kTileHeightIdx];
+}
+
+TileInfo &TileInfo::data_type(DataType dt)
+{
+ _dt = dt;
+ return *this;
+}
+
+DataType TileInfo::data_type() const
+{
+ return _dt;
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TileOperand.cpp b/compute_kernel_writer/src/TileOperand.cpp
new file mode 100644
index 0000000000..8ced6cfe3f
--- /dev/null
+++ b/compute_kernel_writer/src/TileOperand.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2023 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 "ckw/TileOperand.h"
+
+#include "ckw/Error.h"
+
+#include "src/ITile.h"
+
+namespace ckw
+{
+
+TileOperand::TileOperand() : _tile(nullptr), _row_start(0), _row_end(0), _col_start(0), _col_end(0)
+{
+}
+
+TileOperand::TileOperand(ITile &tile)
+ : _tile(&tile), _row_start(0), _row_end(tile.info().height()), _col_start(0), _col_end(tile.info().width())
+{
+}
+
+TileOperand::TileOperand(
+ const TileOperand &operand, int32_t row_start, int32_t row_end, int32_t col_start, int32_t col_end)
+ : _tile(operand._tile), _row_start(row_start), _row_end(row_end), _col_start(col_start), _col_end(col_end)
+{
+ CKW_ASSERT(row_start >= 0 && row_start < _tile->info().height());
+ CKW_ASSERT(row_end > row_start && row_end <= _tile->info().height());
+ CKW_ASSERT(col_start >= 0 && col_start < _tile->info().width());
+ CKW_ASSERT(col_end > col_start && col_end <= _tile->info().width());
+}
+
+bool TileOperand::is_valid() const
+{
+ return _tile != nullptr;
+}
+
+const TileInfo &TileOperand::tile_info() const
+{
+ return _tile->info();
+}
+
+TileOperand TileOperand::tile(int32_t row_start, int32_t row_end, int32_t col_start, int32_t col_end) const
+{
+ CKW_ASSERT(row_start >= 0 && _row_start + row_start < _row_end);
+ CKW_ASSERT(row_end > row_start && _row_start + row_end <= _row_end);
+ CKW_ASSERT(col_start >= 0 && _col_start + col_start < _col_end);
+ CKW_ASSERT(col_end > col_start && _col_start + col_end <= _col_end);
+
+ return TileOperand(*this, _row_start + row_start, _row_start + row_end, _col_start + col_start,
+ _col_start + col_end);
+}
+
+TileOperand TileOperand::row(int32_t row) const
+{
+ CKW_ASSERT(row >= 0 && _row_start + row < _row_end);
+
+ return tile(_row_start + row, _row_start + row + 1, _col_start, _col_end);
+}
+
+TileOperand TileOperand::scalar(int32_t row, int32_t col) const
+{
+ CKW_ASSERT(row >= 0 && _row_start + row < _row_end);
+ CKW_ASSERT(col >= 0 && _col_start + col < _col_end);
+
+ return tile(_row_start + row, _row_start + row + 1, _col_start + col, _col_start + col + 1);
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TileView.cpp b/compute_kernel_writer/src/TileView.cpp
new file mode 100644
index 0000000000..ea803f92f4
--- /dev/null
+++ b/compute_kernel_writer/src/TileView.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023 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 "src/TileView.h"
+
+#include <cstdint>
+
+namespace ckw
+{
+
+TileArea::TileArea(int32_t row_start, int32_t row_end, int32_t col_start, int32_t col_end)
+ : _row_start(row_start), _row_end(row_end), _col_start(col_start), _col_end(col_end)
+{
+}
+
+int32_t TileArea::row_start() const
+{
+ return _row_start;
+}
+
+int32_t TileArea::row_end() const
+{
+ return _row_end;
+}
+
+int32_t TileArea::col_start() const
+{
+ return _col_start;
+}
+
+int32_t TileArea::col_end() const
+{
+ return _col_end;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/TileView.h b/compute_kernel_writer/src/TileView.h
new file mode 100644
index 0000000000..42854ac823
--- /dev/null
+++ b/compute_kernel_writer/src/TileView.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_TILEVIEW_H
+#define CKW_SRC_TILEVIEW_H
+
+#include "ckw/Error.h"
+#include "ckw/types/DataType.h"
+
+#include "src/ITile.h"
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** A rectangular active area of a tile. */
+class TileArea
+{
+public:
+ /** Create a new tile rectangular active area.
+ *
+ * The range of rows and columns is defined by pairs of start and end indices, inclusive lower and exclusive upper.
+ * In other word, any row and column indices satisfied the following conditions will be part of the active area:
+ *
+ * row_start <= row_index < row_end
+ * col_start <= col_index < col_end
+ *
+ * @param[in] row_start The start index of the row range.
+ * @param[in] row_end The end index of the row range.
+ * @param[in] col_start The start index of the column range.
+ * @param[in] col_end The end index of the column range.
+ */
+ TileArea(int32_t row_start, int32_t row_end, int32_t col_start, int32_t col_end);
+
+ /** Get the start row index. */
+ int32_t row_start() const;
+
+ /** Get the end row (exclusive) index. */
+ int32_t row_end() const;
+
+ /** Get the start column index. */
+ int32_t col_start() const;
+
+ /** Get the end column (exclusive) index. */
+ int32_t col_end() const;
+
+private:
+ int32_t _row_start;
+ int32_t _row_end;
+ int32_t _col_start;
+ int32_t _col_end;
+};
+
+/** A rectangular view of a tile. */
+template <typename T>
+class TileView
+{
+public:
+ /** Default constructor */
+ TileView() : _tile(nullptr), _area(0, 0, 0, 0)
+ {
+ }
+ /** Create a tile view that refers to the whole tile.
+ *
+ * @param[in] tile The tile object.
+ */
+ TileView(const T &tile) : _tile(&tile), _area(0, tile.info().height(), 0, tile.info().width())
+ {
+ }
+
+ /** Create a new rectangular view of the given tile.
+ *
+ * @param[in] tile The tile object.
+ * @param[in] area The rectangular active area.
+ */
+ TileView(const T &tile, const TileArea &area) : _tile(&tile), _area(area)
+ {
+ }
+
+ /** Get the tile object.
+ *
+ * The caller must guarantee that the tile view refers to the whole tile.
+ */
+ const T &full_tile() const
+ {
+ CKW_ASSERT(is_full_tile());
+
+ return *_tile;
+ }
+
+ /** Get the data type of the tile. */
+ DataType data_type() const
+ {
+ return _tile->info().data_type();
+ }
+
+ /** Get the start row index. */
+ int32_t row_start() const
+ {
+ return _area.row_start();
+ }
+
+ /** Get the end row index. */
+ int32_t row_end() const
+ {
+ return _area.row_end();
+ }
+
+ /** Get the start column index. */
+ int32_t col_start() const
+ {
+ return _area.col_start();
+ }
+
+ /** Get the end column index. */
+ int32_t col_end() const
+ {
+ return _area.col_end();
+ }
+
+ /** Get the height of the tile view. */
+ int32_t height() const
+ {
+ return _area.row_end() - _area.row_start();
+ }
+
+ /** Get the width of the tile view. */
+ int32_t width() const
+ {
+ return _area.col_end() - _area.col_start();
+ }
+
+ /** See @ref IVectorAccess::vector. */
+ TileVariable vector(int32_t row) const
+ {
+ return _tile->vector(row_start() + row, col_start(), width());
+ }
+
+ /** See @ref IScalarAccess::scalar. */
+ TileVariable scalar(int32_t row, int32_t col) const
+ {
+ return _tile->scalar(row_start() + row, col_start() + col);
+ }
+
+ /** Get the name of the tile. */
+ const std::string &name() const
+ {
+ return _tile->name();
+ }
+
+ /** Get whether the tile view is a scalar element. */
+ bool is_scalar() const
+ {
+ return height() == 1 && width() == 1;
+ }
+
+ /** Get whether the tile view refers to the whole tile. */
+ bool is_full_tile() const
+ {
+ return row_start() == 0 && row_end() == _tile->info().height() && col_start() == 0 &&
+ col_end() == _tile->info().width();
+ }
+
+ /** Set the rectangular active area.
+ *
+ * @param[in] area The rectangular active area.
+ */
+ TileView &area(const TileArea &area)
+ {
+ _area = area;
+ return *this;
+ }
+
+ /** Get the tile area */
+ TileArea area() const
+ {
+ return _area;
+ }
+
+private:
+ const T *_tile;
+ TileArea _area;
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_TILEVIEW_H
diff --git a/compute_kernel_writer/src/cl/CLHelpers.cpp b/compute_kernel_writer/src/cl/CLHelpers.cpp
new file mode 100644
index 0000000000..252c5cdfcb
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLHelpers.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2023 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 "src/cl/CLHelpers.h"
+
+#include "ckw/Error.h"
+#include "ckw/types/DataType.h"
+#include "ckw/types/Operators.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include "src/types/DataTypeHelpers.h"
+
+namespace ckw
+{
+bool cl_validate_vector_length(int32_t len)
+{
+ bool valid_vector_length = true;
+ if (len < 1 || len > 16 || (len > 4 && len < 8) || (len > 8 && len < 16))
+ {
+ valid_vector_length = false;
+ }
+ return valid_vector_length;
+}
+
+std::string cl_get_variable_datatype_as_string(DataType dt, int32_t len)
+{
+ if (cl_validate_vector_length(len) == false)
+ {
+ CKW_THROW_MSG("Unsupported vector length");
+ return "";
+ }
+
+ std::string res;
+ switch (dt)
+ {
+ case DataType::Fp32:
+ res += "float";
+ break;
+ case DataType::Fp16:
+ res += "half";
+ break;
+ case DataType::Int8:
+ res += "char";
+ break;
+ case DataType::Uint8:
+ res += "uchar";
+ break;
+ case DataType::Uint16:
+ res += "ushort";
+ break;
+ case DataType::Int16:
+ res += "short";
+ break;
+ case DataType::Uint32:
+ res += "uint";
+ break;
+ case DataType::Int32:
+ res += "int";
+ break;
+ case DataType::Bool:
+ res += "bool";
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported datatype");
+ return "";
+ }
+
+ if (len > 1)
+ {
+ res += std::to_string(len);
+ }
+
+ return res;
+}
+
+int32_t cl_round_up_to_nearest_valid_vector_width(int32_t width)
+{
+ switch (width)
+ {
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 3;
+ case 4:
+ return 4;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ return 8;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ return 16;
+ default:
+ CKW_THROW_MSG("Unsupported width to convert to OpenCL vector");
+ return 0;
+ }
+}
+
+std::string cl_get_variable_storagetype_as_string(TensorStorageType storage)
+{
+ std::string res;
+ switch (storage)
+ {
+ case TensorStorageType::BufferUint8Ptr:
+ res += "__global uchar*";
+ break;
+ case TensorStorageType::Texture2dReadOnly:
+ res += "__read_only image2d_t";
+ break;
+ case TensorStorageType::Texture2dWriteOnly:
+ res += "__write_only image2d_t";
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported storage type");
+ }
+
+ return res;
+}
+
+std::string cl_get_assignment_op_as_string(AssignmentOp op)
+{
+ switch (op)
+ {
+ case AssignmentOp::Increment:
+ return "+=";
+
+ case AssignmentOp::Decrement:
+ return "-=";
+
+ default:
+ CKW_THROW_MSG("Unsupported assignment operator!");
+ }
+}
+
+std::tuple<bool, std::string> cl_get_unary_op(UnaryOp op)
+{
+ switch (op)
+ {
+ case UnaryOp::LogicalNot:
+ return {false, "!"};
+
+ case UnaryOp::BitwiseNot:
+ return {false, "~"};
+
+ case UnaryOp::Exp:
+ return {true, "exp"};
+
+ case UnaryOp::Tanh:
+ return {true, "tanh"};
+
+ case UnaryOp::Sqrt:
+ return {true, "sqrt"};
+
+ case UnaryOp::Erf:
+ return {true, "erf"};
+
+ case UnaryOp::Fabs:
+ return {true, "fabs"};
+
+ case UnaryOp::Log:
+ return {true, "log"};
+
+ case UnaryOp::Round:
+ return {true, "round"};
+
+ case UnaryOp::Floor:
+ return {true, "floor"};
+
+ default:
+ CKW_THROW_MSG("Unsupported unary operation!");
+ }
+}
+
+std::tuple<bool, std::string> cl_get_binary_op(BinaryOp op, DataType data_type)
+{
+ const auto is_float = is_data_type_float(data_type);
+
+ switch (op)
+ {
+ case BinaryOp::Add:
+ return {false, "+"};
+
+ case BinaryOp::Sub:
+ return {false, "-"};
+
+ case BinaryOp::Mul:
+ return {false, "*"};
+
+ case BinaryOp::Div:
+ return {false, "/"};
+
+ case BinaryOp::Mod:
+ return {false, "%"};
+
+ case BinaryOp::Equal:
+ return {false, "=="};
+
+ case BinaryOp::Less:
+ return {false, "<"};
+
+ case BinaryOp::LessEqual:
+ return {false, "<="};
+
+ case BinaryOp::Greater:
+ return {false, ">"};
+
+ case BinaryOp::GreaterEqual:
+ return {false, ">="};
+
+ case BinaryOp::LogicalAnd:
+ return {false, "&&"};
+
+ case BinaryOp::LogicalOr:
+ return {false, "||"};
+
+ case BinaryOp::BitwiseXOR:
+ return {false, "^"};
+
+ case BinaryOp::Min:
+ return {true, is_float ? "fmin" : "min"};
+
+ case BinaryOp::Max:
+ return {true, is_float ? "fmax" : "max"};
+
+ default:
+ CKW_THROW_MSG("Unsupported binary operator/function!");
+ }
+}
+
+std::tuple<bool, std::string> cl_get_ternary_op(TernaryOp op)
+{
+ switch (op)
+ {
+ case TernaryOp::Select:
+ return {true, "select"};
+
+ case TernaryOp::Clamp:
+ return {true, "clamp"};
+
+ default:
+ CKW_THROW_MSG("Unsupported ternary function!");
+ }
+}
+
+std::string cl_data_type_rounded_up_to_valid_vector_width(DataType dt, int32_t width)
+{
+ std::string data_type;
+ const int32_t w = cl_round_up_to_nearest_valid_vector_width(width);
+ data_type += cl_get_variable_datatype_as_string(dt, 1);
+ if (w != 1)
+ {
+ data_type += std::to_string(w);
+ }
+ return data_type;
+}
+
+std::vector<int32_t> cl_decompose_vector_width(int32_t vector_width)
+{
+ std::vector<int32_t> x;
+
+ switch (vector_width)
+ {
+ case 0:
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 8:
+ case 16:
+ x.push_back(vector_width);
+ break;
+ case 5:
+ x.push_back(4);
+ x.push_back(1);
+ break;
+ case 6:
+ x.push_back(4);
+ x.push_back(2);
+ break;
+ case 7:
+ x.push_back(4);
+ x.push_back(3);
+ break;
+ case 9:
+ x.push_back(8);
+ x.push_back(1);
+ break;
+ case 10:
+ x.push_back(8);
+ x.push_back(2);
+ break;
+ case 11:
+ x.push_back(8);
+ x.push_back(3);
+ break;
+ case 12:
+ x.push_back(8);
+ x.push_back(4);
+ break;
+ case 13:
+ x.push_back(8);
+ x.push_back(4);
+ x.push_back(1);
+ break;
+ case 14:
+ x.push_back(8);
+ x.push_back(4);
+ x.push_back(2);
+ break;
+ case 15:
+ x.push_back(8);
+ x.push_back(4);
+ x.push_back(3);
+ break;
+
+ default:
+ CKW_THROW_MSG("Vector width is too large");
+ }
+ return x;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/CLHelpers.h b/compute_kernel_writer/src/cl/CLHelpers.h
new file mode 100644
index 0000000000..370ffc700c
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLHelpers.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef CKW_SRC_CL_CLHELPERS_H
+#define CKW_SRC_CL_CLHELPERS_H
+
+#include "ckw/types/Operators.h"
+
+#include <cstdint>
+#include <string>
+#include <tuple>
+#include <vector>
+
+/** OpenCL specific helper functions */
+namespace ckw
+{
+// Forward declarations
+enum class DataType;
+enum class TensorStorageType : uint32_t;
+
+/** Helper function to validate the vector length of OpenCL vector data types
+ *
+ * @param[in] len Vector length
+ *
+ * @return true if the vector lenght is valid. It returns false, otherwise.
+ */
+bool cl_validate_vector_length(int32_t len);
+
+/** Helper function to return the OpenCL datatype as a string from a @ref DataType and vector length as int32_t variable
+ *
+ * @param[in] dt Datatype
+ * @param[in] len Vector length
+ *
+ * @return the OpenCL datatype as a string
+ */
+std::string cl_get_variable_datatype_as_string(DataType dt, int32_t len);
+
+/** Return the assignment operator in OpenCL language.
+ *
+ * @param[in] op The assignment operator.
+ *
+ * @return The operator in OpenCL language as a string.
+ */
+std::string cl_get_assignment_op_as_string(AssignmentOp op);
+
+/** Return the information about the unary operation.
+ *
+ * The result contains:
+ * - is_func: true if it's a function and false if it's an unary operator in OpenCL language.
+ * - str: the function name or the operator in OpenCL language.
+ *
+ * @param[in] op The unary operator.
+ *
+ * @return The information about the unary operation.
+ */
+std::tuple<bool, std::string> cl_get_unary_op(UnaryOp op);
+
+/** Return the information about the binary operation.
+ *
+ * The result contains:
+ * - is_func: true if it's a function and false if it's an binary operator in OpenCL language.
+ * - str: the function name or the operator in OpenCL language.
+ *
+ * @param[in] op The binary operator.
+ * @param[in] data_type The input data type.
+ *
+ * @return The information about the binary operation.
+ */
+std::tuple<bool, std::string> cl_get_binary_op(BinaryOp op, DataType data_type);
+
+/** Return the information about the ternary operation.
+ *
+ * The result contains:
+ * - is_func: true if it's a function and false if it's a ternary operator in OpenCL language.
+ * - str: the function name or the operator in OpenCL language.
+ *
+ * @param[in] op The ternary operator.
+ *
+ * @return The information about the ternary operation.
+ */
+std::tuple<bool, std::string> cl_get_ternary_op(TernaryOp op);
+
+/** Helper function to return the OpenCL vector size that accommodate the the desired width
+ *
+ * @param[in] width The desired width
+ *
+ * @return the OpenCL vector size
+*/
+int32_t cl_round_up_to_nearest_valid_vector_width(int32_t width);
+
+/** Helper function to return the OpenCL storage type as a string from a @ref TensorStorage
+ *
+ * @param[in] storage Storage type
+ *
+ * @return the OpenCL storage type as a string
+ */
+std::string cl_get_variable_storagetype_as_string(TensorStorageType storage);
+
+/** Helper function to decompose a vector width into a summation of valid OpenCL vector widths.
+ *
+ * @param[in] vector_width Vector width to be decomposed
+ *
+ * @return a vector of OpenCL vector widths
+ */
+std::vector<int32_t> cl_decompose_vector_width(int32_t vector_width);
+
+/** Helper function to get OpenCL data type from the data type enum and width
+ * It'll round up the given vector width to the nearest valid OpenCL vector width.
+ *
+ * @param[in] dt data type enum
+ * @param[in] width vector width
+ *
+ * @return a string representation of the data type
+ */
+std::string cl_data_type_rounded_up_to_valid_vector_width(DataType dt, int32_t width);
+} // namespace ckw
+
+#endif /* CKW_SRC_CL_CLHELPERS_H */
diff --git a/compute_kernel_writer/src/cl/CLKernelWriter.cpp b/compute_kernel_writer/src/cl/CLKernelWriter.cpp
new file mode 100644
index 0000000000..91512bde23
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLKernelWriter.cpp
@@ -0,0 +1,833 @@
+/*
+ * Copyright (c) 2023-2024 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 "src/cl/CLKernelWriter.h"
+
+#include "ckw/Error.h"
+#include "ckw/Kernel.h"
+#include "ckw/TensorSampler.h"
+#include "ckw/TileOperand.h"
+#include "ckw/types/DataType.h"
+#include "ckw/types/MemoryOperation.h"
+#include "ckw/types/TargetLanguage.h"
+
+#include "src/cl/CLHelpers.h"
+#include "src/cl/CLTensorArgument.h"
+#include "src/cl/CLTile.h"
+#include "src/cl/helpers/CLMemoryOpBufferHelper.h"
+#include "src/cl/helpers/CLMemoryOpImage2dHelper.h"
+#include "src/cl/helpers/ICLMemoryOpHelper.h"
+#include "src/ITensorComponent.h"
+#include "src/TileView.h"
+#include "src/types/DataTypeHelpers.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <tuple>
+#include <vector>
+
+namespace
+{
+std::string generate_cl_extensions()
+{
+ std::string ext = R"(
+#if defined(cl_khr_fp16)
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+#endif // defined(cl_khr_fp16)
+
+#if defined(cl_arm_printf)
+#pragma OPENCL EXTENSION cl_arm_printf : enable
+#endif // defined(cl_arm_printf);
+
+#define inf (INFINITY)
+)";
+ return ext;
+}
+} // namespace
+
+namespace ckw
+{
+
+CLKernelWriter::CLKernelWriter() = default;
+CLKernelWriter::~CLKernelWriter() = default;
+
+std::unique_ptr<Kernel> CLKernelWriter::emit_kernel(const std::string &name)
+{
+ std::string code;
+ code += generate_cl_extensions();
+ code += "__kernel void ";
+ code += name;
+ code += "\n(\n";
+
+ // Create the list of arguments.
+ std::vector<KernelArgument> arguments;
+
+ for (const auto &tensor : _tensors)
+ {
+ const auto tensor_id = tensor->info().id();
+
+ const auto storages = tensor->storages();
+ const auto components = tensor->components();
+
+ for (const auto &storage : storages)
+ {
+ code += cl_get_variable_storagetype_as_string(storage.type);
+ code += " ";
+ code += storage.val;
+ code += ",\n";
+
+ arguments.emplace_back(tensor_id, storage.type);
+ }
+
+ for (const auto &component : components)
+ {
+ const auto &tile = component->tile();
+ const auto &tile_info = tile.info();
+
+ CKW_ASSERT(tile.is_scalar());
+
+ code += cl_get_variable_datatype_as_string(tile_info.data_type(), 1);
+ code += " ";
+ code += tile.name();
+ code += ",\n";
+
+ arguments.emplace_back(tensor_id, component->component_type());
+ }
+ }
+
+ if (code.size() >= 2 && code[code.size() - 2] == ',' && code[code.size() - 1] == '\n')
+ {
+ // Remove the last comma in the argument list.
+ code.pop_back();
+ code[code.size() - 1] = '\n';
+ }
+
+ code += ")\n{\n";
+
+ code += _body_source_code;
+
+ code += "}\n";
+
+ return std::make_unique<Kernel>(TargetLanguage::OpenCL, arguments, code);
+}
+
+void CLKernelWriter::op_assign(const TileOperand &dst, const TileOperand &src)
+{
+ const auto dst_view = to_cl_tile_view(dst);
+ const auto src_view = to_cl_tile_view(src);
+
+ const auto dst_w = dst_view.width();
+ const auto dst_h = dst_view.height();
+ const auto src_w = src_view.width();
+
+ const auto data_type_str = cl_get_variable_datatype_as_string(dst_view.data_type(), dst_w);
+
+ const auto broadcast_src_x = dst_w != 1 && src_w == 1;
+ const std::string src_prefix = broadcast_src_x ? "(" + data_type_str + ")" : "";
+
+ CKW_ASSERT_MSG(src_view.data_type() == dst_view.data_type(), "Source and destination type must match.");
+ CKW_ASSERT_MSG(src_view.height() == dst_h || src_view.height() == 1,
+ "Tile height must match or source is broadcasting in y dimension.");
+ CKW_ASSERT_MSG(src_w == dst_w || src_w == 1, "Tile width must match or source is broadcasting in x dimension.");
+
+ // Broadcasting on y dimension is automatic (see CLTile::vector).
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ append_code(dst_view.vector(y).str, " = ", src_prefix, src_view.vector(y).str, ";\n");
+ }
+}
+
+void CLKernelWriter::op_cast(const TileOperand &dst, const TileOperand &src, ConvertPolicy policy)
+{
+ const auto dst_view = to_cl_tile_view(dst);
+ const auto src_view = to_cl_tile_view(src);
+
+ const auto dst_w = dst_view.width();
+ const auto dst_h = dst_view.height();
+ const auto src_w = src_view.width();
+
+ const auto dst_type = dst_view.data_type();
+
+ const auto convert_type_str = cl_get_variable_datatype_as_string(dst_type, src_w);
+ const auto dst_type_str = cl_get_variable_datatype_as_string(dst_type, dst_w);
+
+ const std::string sat = policy == ConvertPolicy::Saturate ? "_sat" : "";
+
+ CKW_ASSERT_IF(policy == ConvertPolicy::Saturate, !is_data_type_float(dst_type));
+
+ const auto broadcast_x = dst_w != 1 && src_w == 1;
+ const std::string prefix = broadcast_x ? "(" + dst_type_str + ")" : "";
+
+ CKW_ASSERT_MSG(src_view.height() == dst_h || src_view.height() == 1,
+ "Tile height must match or source is broadcasting in y dimension.");
+ CKW_ASSERT_MSG(src_w == dst_w || src_w == 1, "Tile width must match or source is broadcasting in x dimension.");
+
+ // Broadcasting on y dimension is automatic (see CLTile::vector).
+ if (src_view.data_type() == dst_view.data_type())
+ {
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ append_code(dst_view.vector(y).str, " = ", src_view.vector(y).str, ";\n");
+ }
+ }
+ else
+ {
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ append_code(dst_view.vector(y).str, " = ", prefix, "convert_", convert_type_str, sat, "(",
+ src_view.vector(y).str, ");\n");
+ }
+ }
+}
+
+void CLKernelWriter::op_unary(const TileOperand &dst, UnaryOp op, const TileOperand &src)
+{
+ const auto dst_view = to_cl_tile_view(dst);
+ const auto src_view = to_cl_tile_view(src);
+
+ const auto dst_w = dst_view.width();
+ const auto dst_h = dst_view.height();
+ const auto src_w = src_view.width();
+
+ const auto data_type_str = cl_get_variable_datatype_as_string(dst_view.data_type(), dst_w);
+ const auto broadcast_src_x = dst_w != 1 && src_w == 1;
+
+ const std::string src_prefix = broadcast_src_x ? "(" + data_type_str + ")" : "";
+
+ const auto op_info = cl_get_unary_op(op);
+ const auto op_is_func = std::get<0>(op_info);
+ const auto &op_name = std::get<1>(op_info);
+ const auto op_prefix = op_is_func ? op_name + "(" : op_name;
+ const auto op_suffix = op_is_func ? ")" : "";
+
+ CKW_ASSERT_MSG(src_view.data_type() == dst_view.data_type(), "Source and destination type must match.");
+ CKW_ASSERT_MSG(src_view.height() == dst_h || src_view.height() == 1,
+ "Tile height must match or source is broadcasting in y dimension.");
+ CKW_ASSERT_MSG(src_w == dst_w || src_w == 1, "Tile width must match or source is broadcasting in x dimension.");
+
+ // Broadcasting on y dimension is automatic (see CLTile::vector).
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ append_code(dst_view.vector(y).str, " = ", src_prefix, op_prefix, src_view.vector(y).str, op_suffix, ";\n");
+ }
+}
+
+void CLKernelWriter::op_binary(const TileOperand &dst, BinaryOp op, const TileOperand &first, const TileOperand &second)
+{
+ const auto dst_view = to_cl_tile_view(dst);
+ const auto lhs_view = to_cl_tile_view(first);
+ const auto rhs_view = to_cl_tile_view(second);
+
+ const auto dst_w = dst_view.width();
+ const auto dst_h = dst_view.height();
+ const auto lhs_w = lhs_view.width();
+ const auto rhs_w = rhs_view.width();
+
+ const auto data_type = lhs_view.data_type();
+
+ CKW_ASSERT_MSG(lhs_view.data_type() == rhs_view.data_type(), "LHS and RHS type must match.");
+
+ if (op == BinaryOp::MatMul_Nt_T)
+ {
+ CKW_ASSERT_MSG(lhs_view.height() == dst_h, "LHS tile height must match the DST tile height");
+ CKW_ASSERT_MSG(rhs_view.height() == dst_w, "RHS tile height must match the DST tile width");
+ CKW_ASSERT_MSG(lhs_view.width() == rhs_view.width(), "LHS tile width must match the LHS tile width");
+
+ CKW_ASSERT(is_data_type_float(data_type));
+
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ for (int32_t x = 0; x < dst_w; ++x)
+ {
+ for (int32_t k = 0; k < lhs_w; ++k)
+ {
+ append_code(dst_view.scalar(y, x).str, " = fma(", lhs_view.scalar(y, k).str, ", ",
+ rhs_view.scalar(x, k).str, ", ", dst_view.scalar(y, x).str, ");\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ CKW_ASSERT_MSG(lhs_view.height() == dst_h || lhs_view.height() == 1,
+ "LHS tile height must match or source is broadcasting in y dimension.");
+ CKW_ASSERT_MSG(rhs_view.height() == dst_h || rhs_view.height() == 1,
+ "RHS tile height must match or source is broadcasting in y dimension.");
+
+ CKW_ASSERT_MSG(lhs_w == dst_w || lhs_w == 1,
+ "LHS tile width must match destination or LHS is broadcasting in x dimension.");
+ CKW_ASSERT_MSG(rhs_w == dst_w || rhs_w == 1,
+ "RHS tile width must match destination or RHS is broadcasting in x dimension.");
+
+ const auto op_info = cl_get_binary_op(op, data_type);
+ const auto op_is_func = std::get<0>(op_info);
+ const auto &op_name = std::get<1>(op_info);
+
+ const auto data_type_str = cl_get_variable_datatype_as_string(data_type, dst_w);
+
+ const auto broadcast_lhs_x = dst_w != 1 && lhs_w == 1;
+ const auto broadcast_rhs_x = dst_w != 1 && rhs_w == 1;
+
+ const std::string lhs_prefix = broadcast_lhs_x ? "(" + data_type_str + ")" : "";
+ const std::string rhs_prefix = broadcast_rhs_x ? "(" + data_type_str + ")" : "";
+
+ const std::string op_prefix = op_is_func ? " = " + op_name + "(" : " = ";
+ const std::string op_separator = op_is_func ? ", " : " " + op_name + " ";
+ const std::string op_suffix = op_is_func ? ");\n" : ";\n";
+
+ // Broadcasting on y dimension is automatic (see CLTile::vector).
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ append_code(dst_view.vector(y).str, op_prefix, lhs_prefix, lhs_view.vector(y).str, op_separator, rhs_prefix,
+ rhs_view.vector(y).str, op_suffix);
+ }
+ }
+}
+
+void CLKernelWriter::op_ternary(
+ const TileOperand &dst, TernaryOp op, const TileOperand &first, const TileOperand &second, const TileOperand &third)
+{
+ const auto dst_view = to_cl_tile_view(dst);
+ const auto first_view = to_cl_tile_view(first);
+ const auto second_view = to_cl_tile_view(second);
+ const auto third_view = to_cl_tile_view(third);
+
+ const auto dst_w = dst_view.width();
+ const auto dst_h = dst_view.height();
+ const auto first_w = first_view.width();
+ const auto second_w = second_view.width();
+ const auto third_w = third_view.width();
+
+ const auto data_type = dst_view.data_type();
+ const auto data_type_str = cl_get_variable_datatype_as_string(data_type, dst_w);
+
+ const auto op_info = cl_get_ternary_op(op);
+ const auto op_is_func = std::get<0>(op_info);
+ const auto &op_name = std::get<1>(op_info);
+
+ const auto broadcast_first_x = dst_w != 1 && first_w == 1;
+ const auto broadcast_second_x = dst_w != 1 && second_w == 1;
+ const auto broadcast_third_x = dst_w != 1 && third_w == 1;
+
+ const std::string first_prefix = broadcast_first_x ? "(" + data_type_str + ")" : "";
+ const std::string second_prefix = broadcast_second_x ? "(" + data_type_str + ")" : "";
+ const std::string third_prefix = broadcast_third_x ? "(" + data_type_str + ")" : "";
+
+ CKW_UNUSED(op_is_func);
+ CKW_ASSERT_MSG(op_is_func, "The only supported ternary operator is function.");
+ CKW_ASSERT_MSG(second_view.data_type() == dst_view.data_type(), "2nd source and destination type must match.");
+ CKW_ASSERT_MSG(third_view.data_type() == dst_view.data_type(), "3rd source and destination type must match.");
+
+ CKW_ASSERT_MSG(first_view.height() == dst_h || first_view.height() == 1,
+ "1st tile height must match or source is broadcasting in y dimension.");
+ CKW_ASSERT_MSG(second_view.height() == dst_h || second_view.height() == 1,
+ "2nd tile height must match or source is broadcasting in y dimension.");
+ CKW_ASSERT_MSG(third_view.height() == dst_h || third_view.height() == 1,
+ "3rd tile height must match or source is broadcasting in y dimension.");
+
+ CKW_ASSERT_MSG(first_w == dst_w || first_w == 1,
+ "1st tile width must match or source is broadcasting in x dimension.");
+ CKW_ASSERT_MSG(second_w == dst_w || second_w == 1,
+ "2nd tile width must match or source is broadcasting in x dimension.");
+ CKW_ASSERT_MSG(third_w == dst_w || third_w == 1,
+ "3rd tile width must match or source is broadcasting in x dimension.");
+
+ // Broadcasting on y dimension is automatic (see CLTile::vector).
+ for (int32_t y = 0; y < dst_h; ++y)
+ {
+ append_code(dst_view.vector(y).str, " = ", op_name, "(", first_prefix, first_view.vector(y).str, ", ",
+ second_prefix, second_view.vector(y).str, ", ", third_prefix, third_view.vector(y).str, ");\n");
+ }
+}
+
+void CLKernelWriter::op_if_generic(
+ const TileOperand &lhs, BinaryOp op, const TileOperand &rhs, const std::function<void()> &body, bool is_else_if)
+{
+ const auto lhs_view = to_cl_tile_view(lhs);
+ const auto rhs_view = to_cl_tile_view(rhs);
+
+ const auto op_name = std::get<1>(cl_get_binary_op(op, lhs_view.data_type()));
+ CKW_ASSERT(op == BinaryOp::Less || op == BinaryOp::LessEqual || op == BinaryOp::Equal ||
+ op == BinaryOp::GreaterEqual || op == BinaryOp::Greater);
+
+ CKW_ASSERT(lhs_view.is_scalar());
+ CKW_ASSERT(rhs_view.is_scalar());
+
+ if (is_else_if)
+ {
+ append_code("else ");
+ }
+
+ append_code("if (", lhs_view.scalar(0, 0).str, " ", op_name, " ", rhs_view.scalar(0, 0).str, ")\n{\n");
+ write_body(body);
+ append_code("}\n");
+}
+
+void CLKernelWriter::op_if(const TileOperand &lhs,
+ BinaryOp op,
+ const TileOperand &rhs,
+ const std::function<void()> &body)
+{
+ op_if_generic(lhs, op, rhs, body, false /* is_else_if */);
+}
+
+void CLKernelWriter::op_else_if(const TileOperand &lhs,
+ BinaryOp op,
+ const TileOperand &rhs,
+ const std::function<void()> &body)
+{
+ op_if_generic(lhs, op, rhs, body, true /* is_else_if */);
+}
+
+void CLKernelWriter::op_else(const std::function<void()> &body)
+{
+ append_code("else\n{\n");
+ write_body(body);
+ append_code("}\n");
+}
+
+void CLKernelWriter::op_for_loop(const TileOperand &var,
+ BinaryOp cond_op,
+ const TileOperand &cond_value,
+ const TileOperand &update_var,
+ AssignmentOp update_op,
+ const TileOperand &update_value,
+ const std::function<void()> &body)
+{
+ const auto var_view = to_cl_tile_view(var);
+ const auto cond_value_view = to_cl_tile_view(cond_value);
+ const auto update_var_view = to_cl_tile_view(update_var);
+ const auto update_value_view = to_cl_tile_view(update_value);
+
+ CKW_ASSERT(var_view.is_scalar());
+ CKW_ASSERT(cond_value_view.is_scalar());
+ CKW_ASSERT(update_var_view.is_scalar());
+ CKW_ASSERT(update_value_view.is_scalar());
+
+ CKW_ASSERT(var_view.data_type() == cond_value_view.data_type());
+ CKW_ASSERT(update_var_view.data_type() == update_value_view.data_type());
+
+ const auto cond_op_name = std::get<1>(cl_get_binary_op(cond_op, var_view.data_type()));
+ CKW_ASSERT(cond_op == BinaryOp::Less || cond_op == BinaryOp::LessEqual || cond_op == BinaryOp::Equal ||
+ cond_op == BinaryOp::GreaterEqual || cond_op == BinaryOp::Greater);
+
+ append_code("for (; ", var_view.scalar(0, 0).str, " ", cond_op_name, " ", cond_value_view.scalar(0, 0).str, "; ",
+ update_var_view.scalar(0, 0).str, " ", cl_get_assignment_op_as_string(update_op), " ",
+ update_value_view.scalar(0, 0).str, ")\n{\n");
+ write_body(body);
+ append_code("}\n");
+}
+
+void CLKernelWriter::op_return()
+{
+ append_code("return;\n");
+}
+
+void CLKernelWriter::op_get_global_id(const TileOperand &dst, int32_t dim)
+{
+ const auto tile_view = to_cl_tile_view(dst);
+
+ CKW_ASSERT(tile_view.is_scalar());
+ CKW_ASSERT(tile_view.data_type() == DataType::Int32 || tile_view.data_type() == DataType::Uint32);
+
+ CKW_ASSERT(dim >= 0 && dim <= 2);
+
+ append_code(tile_view.scalar(0, 0).str, " = get_global_id(", std::to_string(dim), ");\n");
+}
+
+void CLKernelWriter::op_print(const std::string &prefix, const std::vector<TileOperand> &operands)
+{
+ std::string format_code;
+ std::string args_code;
+
+ for (auto &op : operands)
+ {
+ const auto tile_view = to_cl_tile_view(op);
+
+ const auto name = tile_view.name();
+ const auto width = tile_view.width();
+ const auto height = tile_view.height();
+ const auto data_type = tile_view.data_type();
+
+ // Construct the format specifier to print out one row of the tile.
+ std::string row_format("%");
+
+ if (width > 1)
+ {
+ row_format += "v" + std::to_string(width);
+ }
+
+ switch (data_type)
+ {
+ case DataType::Fp32:
+ row_format += "hlg";
+ break;
+ case DataType::Fp16:
+ row_format += "hg";
+ break;
+ case DataType::Int32:
+ case DataType::Bool:
+ row_format += (width > 1) ? "hli" : "i";
+ break;
+ case DataType::Int16:
+ row_format += "hi";
+ break;
+ case DataType::Int8:
+ row_format += "hhi";
+ break;
+ case DataType::Uint32:
+ row_format += (width > 1) ? "hlu" : "u";
+ break;
+ case DataType::Uint16:
+ row_format += "hu";
+ break;
+ case DataType::Uint8:
+ row_format += "hhu";
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported data type!");
+ }
+
+ if (width > 1)
+ {
+ row_format = "[" + row_format + "]";
+ }
+
+ // Construct the format specifier for the printf statement.
+ format_code += name + " = ";
+
+ if (height == 1)
+ {
+ format_code += row_format;
+ }
+ else
+ {
+ format_code += "[" + row_format;
+ for (int32_t row = 1; row < height; ++row)
+ {
+ format_code += ", " + row_format;
+ }
+ format_code += "]";
+ }
+
+ format_code += "\\n";
+
+ // Construct the variable arguments for the printf statement.
+ for (int32_t row = 0; row < height; ++row)
+ {
+ args_code += ", " + tile_view.vector(row).str;
+ }
+ }
+
+ append_code("printf(\"", prefix, "\\n", format_code, "\"", args_code, ");\n");
+}
+
+void CLKernelWriter::op_comment(const std::string &text)
+{
+#ifdef COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+
+ CKW_ASSERT(text.find("\n") == text.npos);
+ CKW_ASSERT(text.find("\r") == text.npos);
+
+ append_code("// ", text, "\n");
+
+#else // COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+
+ CKW_UNUSED(text);
+
+#endif // COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+}
+
+const std::string &CLKernelWriter::body_source_code() const
+{
+ return _body_source_code;
+}
+
+TensorOperand CLKernelWriter::declare_tensor_argument(const std::string &name, const TensorInfo &info)
+{
+ const auto fullname = generate_full_name(name);
+
+ auto tensor = std::make_unique<CLTensorArgument>(fullname, info, false /* return_dims_by_value */);
+ const auto operand = create_tensor_operand(*tensor);
+
+ _tensors.insert(std::move(tensor));
+
+ return operand;
+}
+
+TileOperand CLKernelWriter::declare_tile(const std::string &name, const TileInfo &tile_info)
+{
+ const std::string fullname = generate_full_name(name);
+
+ const int32_t height = tile_info.height();
+ const int32_t width = tile_info.width();
+ const DataType data_type = tile_info.data_type();
+
+ CKW_ASSERT_MSG(std::find_if(_tiles.begin(), _tiles.end(),
+ [=](const std::unique_ptr<CLTile> &e)
+ { return e->name() == fullname; }) == _tiles.end(),
+ "There is already a tile with name: " + fullname);
+
+ auto tile = std::make_unique<CLTile>(fullname, tile_info);
+
+ for (int32_t row = 0; row < height; ++row)
+ {
+ const std::string cl_type = cl_get_variable_datatype_as_string(data_type, width);
+ append_code(cl_type, " ", tile->vector(row).str, ";\n");
+ }
+
+ const auto operand = create_tile_operand(*tile);
+
+ _tiles.insert(std::move(tile));
+
+ return operand;
+}
+
+TileOperand CLKernelWriter::declare_constant_tile(const ConstantData &data)
+{
+ auto tile = std::make_unique<CLTile>(get_values(data), get_data_type(data));
+ const TileOperand operand = create_tile_operand(*tile);
+ _constant_tiles.insert(std::move(tile));
+
+ return operand;
+}
+
+void CLKernelWriter::op_write_raw_code(const std::string &raw_code)
+{
+ append_code(raw_code);
+}
+
+TileView<CLTile> CLKernelWriter::to_cl_tile_view(const TileOperand &operand) const
+{
+ const auto tile_and_area = get_tile(operand);
+ ITile &tile = std::get<0>(tile_and_area);
+ const TileArea area = std::get<1>(tile_and_area);
+
+#ifdef COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+ // Check if the tile is a CLTile created by this kernel writer.
+
+ {
+ bool found = false;
+
+ for (const auto &t : _tiles)
+ {
+ if (&tile == t.get())
+ {
+ found = true;
+ break;
+ }
+ }
+
+ for (const auto &t : _constant_tiles)
+ {
+ if (&tile == t.get())
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ for (const auto &t : _tensors)
+ {
+ const auto components = t->components();
+
+ for (const auto component : components)
+ {
+ if (&tile == &component->tile())
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ break;
+ }
+ }
+ }
+
+ CKW_ASSERT_MSG(found, "The tile is not found!");
+ }
+#endif // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+
+ return {static_cast<CLTile &>(tile), area};
+}
+
+void CLKernelWriter::op_load(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch)
+{
+ const CLTile dilation_x({{"1"}}, DataType::Int32);
+ const CLTile dilation_y({{"1"}}, DataType::Int32);
+
+ op_load_store(MemoryOperation::Load, tile_op, tensor_op, sampler, x, y, z, batch, dilation_x, dilation_y,
+ false /* indirect buffer */);
+}
+
+void CLKernelWriter::op_load_dilated(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileOperand &dilation_x,
+ const TileOperand &dilation_y)
+{
+ const auto dil_x_view = to_cl_tile_view(dilation_x);
+ const auto dil_y_view = to_cl_tile_view(dilation_y);
+
+ op_load_store(MemoryOperation::Load, tile_op, tensor_op, sampler, x, y, z, batch, dil_x_view, dil_y_view,
+ false /* indirect buffer */);
+}
+
+void CLKernelWriter::op_store(const TensorOperand &tensor_op,
+ const TileOperand &tile_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch)
+{
+ const CLTile dilation_x({{"1"}}, DataType::Int32);
+ const CLTile dilation_y({{"1"}}, DataType::Int32);
+
+ op_load_store(MemoryOperation::Store, tile_op, tensor_op, sampler, x, y, z, batch, dilation_x, dilation_y,
+ false /* indirect buffer */);
+}
+
+void CLKernelWriter::op_store_dilated(const TensorOperand &tensor_op,
+ const TileOperand &tile_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileOperand &dilation_x,
+ const TileOperand &dilation_y)
+{
+ const auto dil_x_view = to_cl_tile_view(dilation_x);
+ const auto dil_y_view = to_cl_tile_view(dilation_y);
+
+ op_load_store(MemoryOperation::Store, tile_op, tensor_op, sampler, x, y, z, batch, dil_x_view, dil_y_view,
+ false /* indirect buffer */);
+}
+
+void CLKernelWriter::op_load_indirect(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch)
+{
+ const CLTile dilation_x({{"1"}}, DataType::Int32);
+ const CLTile dilation_y({{"1"}}, DataType::Int32);
+
+ op_load_store(MemoryOperation::Load, tile_op, tensor_op, sampler, x, y, z, batch, dilation_x, dilation_y,
+ true /* indirect buffer */);
+}
+
+void CLKernelWriter::op_load_store(MemoryOperation op,
+ const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileView<CLTile> &dilation_x,
+ const TileView<CLTile> &dilation_y,
+ bool indirect_buffer)
+{
+ CKW_UNUSED(dilation_x);
+ CKW_ASSERT(dilation_x.is_scalar());
+ CKW_ASSERT(dilation_y.is_scalar());
+ CKW_ASSERT(dilation_x.scalar(0, 0).str == "((int)(1))"); // Dilation in x dimension is not implemented yet
+
+ if (indirect_buffer)
+ {
+ CKW_ASSERT(dilation_y.scalar(0, 0).str == "((int)(1))" && dilation_x.scalar(0, 0).str == "((int)(1))");
+ }
+
+ ITensor &tensor = get_tensor(tensor_op);
+
+ const auto tile = to_cl_tile_view(tile_op);
+ const auto x_tile = to_cl_tile_view(x).full_tile();
+ const auto y_tile = to_cl_tile_view(y).full_tile();
+ const auto z_tile = to_cl_tile_view(z).full_tile();
+ const auto batch_tile = to_cl_tile_view(batch).full_tile();
+
+ std::unique_ptr<ICLMemoryOpHelper> helper;
+ switch (sampler.storage())
+ {
+ case TensorStorageType::BufferUint8Ptr:
+ helper = std::make_unique<CLMemoryOpBufferHelper>(this, &tensor, &sampler, op, tile);
+ break;
+ case TensorStorageType::Texture2dReadOnly:
+ case TensorStorageType::Texture2dWriteOnly:
+ helper = std::make_unique<CLMemoryOpImage2dHelper>(this, &tensor, &sampler, op, tile);
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported tensor storage");
+ }
+
+ CKW_ASSERT(x_tile.is_scalar());
+ CKW_ASSERT(z_tile.is_scalar());
+ CKW_ASSERT_IF(indirect_buffer, y_tile.info().width() == 1);
+ CKW_ASSERT_IF(!indirect_buffer, y_tile.is_scalar());
+ CKW_ASSERT(batch_tile.is_scalar());
+
+ helper->initialize(&x_tile, &z_tile, &batch_tile);
+
+ for (int row = 0; row < tile.height(); ++row)
+ {
+ if (!indirect_buffer)
+ {
+ std::string coord_y = y_tile.scalar(0, 0).str + " + " + std::to_string(row);
+
+ if (dilation_y.scalar(0, 0).str != "((int)(1))")
+ {
+ coord_y += " * " + dilation_y.scalar(0, 0).str;
+ }
+
+ helper->write_row(row, coord_y);
+ }
+ else
+ {
+ helper->write_row(row, y_tile.scalar(row, 0).str);
+ }
+ }
+
+ helper->finalize();
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/CLKernelWriter.h b/compute_kernel_writer/src/cl/CLKernelWriter.h
new file mode 100644
index 0000000000..6485bae512
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLKernelWriter.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_CL_CLKERNELWRITER_H
+#define CKW_SRC_CL_CLKERNELWRITER_H
+
+#include "ckw/KernelWriter.h"
+
+#include "src/TileView.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+
+namespace ckw
+{
+
+// Forward Declarations
+class CLTile;
+class CLTensorArgument;
+class ConstantData;
+class TensorOperand;
+class TensorSampler;
+class TileOperand;
+
+enum class DataType;
+enum class MemoryOperation;
+
+/** OpenCL kernel writer. */
+class CLKernelWriter : public KernelWriter
+{
+public:
+ // =============================================================================================
+ // Construtors and destructor
+ // =============================================================================================
+
+ /** Initialize a new instance of @ref CLKernelWriter class. */
+ CLKernelWriter();
+
+ /** Destructor */
+ ~CLKernelWriter();
+
+ // =============================================================================================
+ // Data processing
+ // =============================================================================================
+
+ void op_assign(const TileOperand &dst, const TileOperand &src) override;
+
+ void op_cast(const TileOperand &dst, const TileOperand &src, ConvertPolicy policy) override;
+
+ void op_unary(const TileOperand &dst, UnaryOp op, const TileOperand &src) override;
+
+ void op_binary(const TileOperand &dst, BinaryOp op, const TileOperand &first, const TileOperand &second) override;
+
+ void op_ternary(const TileOperand &dst,
+ TernaryOp op,
+ const TileOperand &first,
+ const TileOperand &second,
+ const TileOperand &third) override;
+
+ // =============================================================================================
+ // Flow control
+ // =============================================================================================
+
+ void op_if(const TileOperand &lhs, BinaryOp op, const TileOperand &rhs, const std::function<void()> &body) override;
+
+ void
+ op_else_if(const TileOperand &lhs, BinaryOp op, const TileOperand &rhs, const std::function<void()> &body) override;
+
+ void op_else(const std::function<void()> &body) override;
+
+ void op_for_loop(const TileOperand &var,
+ BinaryOp cond_op,
+ const TileOperand &cond_value,
+ const TileOperand &update_var,
+ AssignmentOp update_op,
+ const TileOperand &update_value,
+ const std::function<void()> &body) override;
+
+ void op_return() override;
+
+ // =============================================================================================
+ // Misc
+ // =============================================================================================
+
+ void op_get_global_id(const TileOperand &dst, int32_t dim) override;
+
+ void op_comment(const std::string &text) override;
+
+ void op_write_raw_code(const std::string &raw_code) override;
+
+ void op_print(const std::string &prefix, const std::vector<TileOperand> &operands) override;
+
+ // =============================================================================================
+ // Code generation
+ // =============================================================================================
+
+ std::unique_ptr<Kernel> emit_kernel(const std::string &name) override;
+
+ // =============================================================================================
+ // Tensor and tile declaration
+ // =============================================================================================
+
+ TensorOperand declare_tensor_argument(const std::string &name, const TensorInfo &info) override;
+
+ /** Declare a tile given name and tile information
+ *
+ * Similar to @ref KernelWriter::declare_tile()
+ */
+ TileOperand declare_tile(const std::string &name, const TileInfo &tile_info) override;
+
+ /** Declare a constant tile given a @ref:ConstantData object
+ *
+ * Similar to @ref KernelWriter::declare_constant_tile()
+ */
+ TileOperand declare_constant_tile(const ConstantData &data) override;
+
+ // =============================================================================================
+ // Memory Operations
+ // =============================================================================================
+
+ void op_load(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch) override;
+
+ void op_load_dilated(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileOperand &dilation_x,
+ const TileOperand &dilation_y) override;
+
+ void op_store(const TensorOperand &tensor_op,
+ const TileOperand &tile_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch) override;
+
+ void op_store_dilated(const TensorOperand &tensor_op,
+ const TileOperand &tile_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileOperand &dilation_x,
+ const TileOperand &dilation_y) override;
+
+ void op_load_indirect(const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch) override;
+
+protected:
+ /** Return a tile view containing a reference to @ref CLTile object and the active area.
+ *
+ * This function performs appropriate check before doing type casting.
+ */
+ TileView<CLTile> to_cl_tile_view(const TileOperand &operand) const;
+
+ /** Append the specified code to the kernel body source code. */
+ template <typename T, typename... TArgs>
+ void append_code(T &&code, TArgs &&...args)
+ {
+ append_code(std::forward<T>(code));
+ append_code(std::forward<TArgs>(args)...);
+ }
+
+ /** Append the specified code to the kernel body source code. */
+ template <typename T>
+ void append_code(T &&code)
+ {
+ _body_source_code += std::forward<T>(code);
+ }
+
+ /** Get the current kernel body source code. */
+ const std::string &body_source_code() const;
+
+ // For helper functions
+private:
+ /** Helper method to consolidate all load/store logic in this class */
+ void op_load_store(MemoryOperation op,
+ const TileOperand &tile_op,
+ const TensorOperand &tensor_op,
+ TensorSampler &sampler,
+ const TileOperand &x,
+ const TileOperand &y,
+ const TileOperand &z,
+ const TileOperand &batch,
+ const TileView<CLTile> &dilation_x,
+ const TileView<CLTile> &dilation_y,
+ bool indirect_buffer);
+
+ /** This function is the generic function to write both `if` and `else if` blocks.
+ *
+ * It is used for both @ref CLKernelWriter::op_if and @ref CLKernelWriter::op_else_if.
+ *
+ * @param[in] lhs The LHS tile of the condition.
+ * @param[in] op The relational binary operator.
+ * @param[in] rhs The RHS tile of the condition.
+ * @param[in] body The function that writes the body of the else-if block.
+ * @param[in] is_else_if True if this is an `else if` block, otherwise this is an `if` block.
+ */
+ void op_if_generic(const TileOperand &lhs,
+ BinaryOp op,
+ const TileOperand &rhs,
+ const std::function<void()> &body,
+ bool is_else_if);
+
+ // For attributes
+private:
+ /** This string contains the kernel body source code, not the full CL source code.
+ * The full source code will only be generated when the user calls @ref KernelWriter::emit_kernel.
+ *
+ * In order to add code to this, use @ref CLKernelWriter::append_code.
+ * Do not attempt to concatenate and alter this string directly.
+ */
+ std::string _body_source_code{};
+
+ std::set<std::unique_ptr<CLTensorArgument>> _tensors{};
+ std::set<std::unique_ptr<CLTile>> _tiles{};
+ std::set<std::unique_ptr<CLTile>> _constant_tiles{};
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_CL_CLKERNELWRITER_H
diff --git a/compute_kernel_writer/src/cl/CLTensorArgument.cpp b/compute_kernel_writer/src/cl/CLTensorArgument.cpp
new file mode 100644
index 0000000000..e53de2830d
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLTensorArgument.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2023 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 "src/cl/CLTensorArgument.h"
+
+#include "ckw/Error.h"
+
+#include "src/cl/CLHelpers.h"
+#include "src/cl/CLTensorComponent.h"
+#include "src/ITensorArgument.h"
+#include "src/ITensorComponent.h"
+#include "src/types/TensorComponentType.h"
+
+#include <algorithm>
+#include <vector>
+
+namespace ckw
+{
+CLTensorArgument::CLTensorArgument(const std::string &name, const TensorInfo &info, bool return_dims_by_value)
+{
+ _return_dims_by_value = return_dims_by_value;
+ _basename = name;
+ _info = info;
+}
+
+CLTensorArgument::~CLTensorArgument() = default;
+
+CLTensorComponent &CLTensorArgument::cl_component(TensorComponentType x)
+{
+ // Return the component if it has already been created.
+ {
+ const auto it =
+ std::find_if(_components_used.begin(), _components_used.end(),
+ [=](const std::unique_ptr<CLTensorComponent> &item) { return item->component_type() == x; });
+
+ if (it != _components_used.end())
+ {
+ return **it;
+ }
+ }
+
+ if (_return_dims_by_value)
+ {
+ uint32_t component_type = static_cast<uint32_t>(x);
+
+ const bool is_dimension = (component_type & static_cast<uint32_t>(TensorComponentBitmask::Dimension)) != 0;
+ const bool is_folded_dimensions =
+ (component_type & static_cast<uint32_t>(TensorComponentBitmask::FoldedDimensions)) != 0;
+
+ constexpr auto bitmask_all = static_cast<uint32_t>(TensorComponentIndexBitmask::All);
+ constexpr auto bitmask_index_0 = static_cast<uint32_t>(TensorComponentIndexBitmask::Index0);
+#ifdef COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+ constexpr auto bitmask_index_1 = static_cast<uint32_t>(TensorComponentIndexBitmask::Index1);
+ constexpr auto bitmask_index_2 = static_cast<uint32_t>(TensorComponentIndexBitmask::Index2);
+ constexpr auto bitmask_index_3 = static_cast<uint32_t>(TensorComponentIndexBitmask::Index3);
+#endif // COMPUTE_KERNEL_WRITER_ASSERTS_ENABLED
+
+ // Make sure that the encoding of component type hasn't changed and each nibble is 4 bits apart.
+ CKW_ASSERT(bitmask_all == (bitmask_index_0 | bitmask_index_1 | bitmask_index_2 | bitmask_index_3));
+ CKW_ASSERT(bitmask_index_0 == bitmask_index_1 >> 4);
+ CKW_ASSERT(bitmask_index_1 == bitmask_index_2 >> 4);
+ CKW_ASSERT(bitmask_index_2 == bitmask_index_3 >> 4);
+
+ // If we have a dimension or folded dimensions, we can return the corresponding value if it is not dynamic (not equal to -1)
+ if (is_dimension == true || is_folded_dimensions == true)
+ {
+ component_type = component_type & bitmask_all;
+
+ int32_t idx = 1;
+ for (int32_t i = 0; i < tensor_component_index_max_count; ++i)
+ {
+ uint32_t dim_idx = component_type & bitmask_index_0;
+
+ if (dim_idx == 0)
+ {
+ // Stop at the first nibble containing 0
+ break;
+ }
+
+ // Subtract - 1. Please refer to the TensorComponentIndexBitmask documentation
+ dim_idx -= 1;
+
+ // Get the dimension value
+ const int32_t dim_val = _info.shape()[dim_idx];
+
+ if (dim_val == kDynamicTensorDimensionValue)
+ {
+ // We cannot return the dimension by value if it is dynamic.
+ // Therefore, force the idx variable to kDynamicTensorDimensionValue and break the loop.
+ idx = kDynamicTensorDimensionValue;
+ break;
+ }
+
+ idx *= dim_val;
+
+ // Go to the next nibble
+ component_type >>= 4;
+ }
+
+ if (idx != kDynamicTensorDimensionValue)
+ {
+ _components_used.emplace_back(std::make_unique<CLTensorComponent>(*this, x, idx));
+
+ return *_components_used.back();
+ }
+ }
+ }
+
+ _components_used.emplace_back(std::make_unique<CLTensorComponent>(*this, x));
+
+ return *_components_used.back();
+}
+
+ITile &CLTensorArgument::component(TensorComponentType x)
+{
+ return cl_component(x);
+}
+
+TensorStorageVariable &CLTensorArgument::storage(TensorStorageType x)
+{
+ // Return the storage if it has already been created.
+ {
+ const auto it = std::find_if(_storages_used.begin(), _storages_used.end(),
+ [=](const TensorStorageVariable &item) { return item.type == x; });
+
+ if (it != _storages_used.end())
+ {
+ return *it;
+ }
+ }
+
+ TensorStorageVariable t;
+ t.val = create_storage_name(x);
+ t.type = x;
+
+ _storages_used.emplace_back(t);
+
+ return _storages_used.back();
+}
+
+std::string CLTensorArgument::create_storage_name(TensorStorageType x) const
+{
+ std::string var_name = _basename;
+
+ switch (x)
+ {
+ case TensorStorageType::BufferUint8Ptr:
+ var_name += "_ptr";
+ break;
+ case TensorStorageType::Texture2dReadOnly:
+ case TensorStorageType::Texture2dWriteOnly:
+ var_name += "_img2d";
+ break;
+ default:
+ CKW_ASSERT_FAILED_MSG("Unsupported tensor storage");
+ return "";
+ }
+
+ return var_name;
+}
+
+std::vector<TensorStorageVariable> CLTensorArgument::storages() const
+{
+ std::vector<TensorStorageVariable> storages;
+ storages.reserve(_storages_used.size());
+
+ std::copy(_storages_used.begin(), _storages_used.end(), std::back_inserter(storages));
+
+ return storages;
+}
+
+std::vector<const ITensorComponent *> CLTensorArgument::components() const
+{
+ std::vector<const ITensorComponent *> components;
+
+ for (const auto &component : _components_used)
+ {
+ if (component->is_assignable())
+ {
+ components.push_back(component.get());
+ }
+ }
+
+ return components;
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/CLTensorArgument.h b/compute_kernel_writer/src/cl/CLTensorArgument.h
new file mode 100644
index 0000000000..a79cf340bb
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLTensorArgument.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef CKW_SRC_CL_CLTENSORARGUMENT_H
+#define CKW_SRC_CL_CLTENSORARGUMENT_H
+
+#include "ckw/types/TensorComponentType.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include "src/cl/CLTensorComponent.h"
+#include "src/ITensor.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+// Forward declarations
+class TensorInfo;
+
+class ITensorComponent;
+
+/** OpenCL specific tensor argument
+ * Internally, the object keeps track of the components and storages used to minimize the number
+ * of kernel arguments required. Therefore, if we create this object but we do not access any components
+ * or storages, the storages() and components() method will return an empty list.
+*/
+class CLTensorArgument : public ITensor
+{
+public:
+ /** Constructor
+ *
+ * @param[in] name Tensor name
+ * @param[in] info Tensor info
+ * @param[in] return_dims_by_value Flag to return the dimensions by value whenever it is possible.
+ * True, if the dimensions should be returned as value instead as variable.
+ */
+ CLTensorArgument(const std::string &name, const TensorInfo &info, bool return_dims_by_value);
+
+ /** Destructor. */
+ ~CLTensorArgument();
+
+ /** Get a tensor component of the given type.
+ *
+ * This function is for internal use as it returns a reference to @ref CLTensorComponent object.
+ * It provides rich functionalities and doesn't require unnecessary casting
+ * unlike @ref CLTensorComponent::component which is for the public API and only returns
+ * a reference to a generic @ref ITile object.
+ */
+ CLTensorComponent &cl_component(TensorComponentType component_type);
+
+ // Inherited method overridden
+ TensorStorageVariable &storage(TensorStorageType x) override;
+ ITile &component(TensorComponentType x) override;
+ std::vector<TensorStorageVariable> storages() const override;
+ std::vector<const ITensorComponent *> components() const override;
+
+private:
+ std::string create_storage_name(TensorStorageType x) const;
+
+ bool _return_dims_by_value{false};
+ std::vector<TensorStorageVariable> _storages_used{};
+ std::vector<std::unique_ptr<CLTensorComponent>> _components_used{};
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_CL_CLTENSORARGUMENT_H
diff --git a/compute_kernel_writer/src/cl/CLTensorComponent.cpp b/compute_kernel_writer/src/cl/CLTensorComponent.cpp
new file mode 100644
index 0000000000..dbe2036768
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLTensorComponent.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2023 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 "src/cl/CLTensorComponent.h"
+
+#include "ckw/Error.h"
+#include "ckw/types/TensorComponentType.h"
+
+#include "src/cl/CLTensorArgument.h"
+#include "src/cl/CLTile.h"
+
+namespace ckw
+{
+
+namespace
+{
+
+std::string create_component_name(const std::string &name, TensorComponentType x)
+{
+ std::string var_name(name);
+
+ switch (x)
+ {
+ case TensorComponentType::OffsetFirstElement:
+ var_name += "_offset_first_element";
+ break;
+ case TensorComponentType::Stride0:
+ var_name += "_stride0";
+ break;
+ case TensorComponentType::Stride1:
+ var_name += "_stride1";
+ break;
+ case TensorComponentType::Stride2:
+ var_name += "_stride2";
+ break;
+ case TensorComponentType::Stride3:
+ var_name += "_stride3";
+ break;
+ case TensorComponentType::Stride4:
+ var_name += "_stride4";
+ break;
+ case TensorComponentType::Dim0:
+ var_name += "_dim0";
+ break;
+ case TensorComponentType::Dim1:
+ var_name += "_dim1";
+ break;
+ case TensorComponentType::Dim2:
+ var_name += "_dim2";
+ break;
+ case TensorComponentType::Dim3:
+ var_name += "_dim3";
+ break;
+ case TensorComponentType::Dim4:
+ var_name += "_dim4";
+ break;
+ case TensorComponentType::Dim1xDim2:
+ var_name += "_dim1xdim2";
+ break;
+ case TensorComponentType::Dim2xDim3:
+ var_name += "_dim2xdim3";
+ break;
+ case TensorComponentType::Dim1xDim2xDim3:
+ var_name += "_dim1xdim2xdim3";
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported tensor component");
+ return "";
+ }
+
+ return var_name;
+}
+
+} // namespace
+
+CLTensorComponent::CLTensorComponent(const CLTensorArgument &tensor, TensorComponentType component_type)
+ : CLTile(create_component_name(tensor.name(), component_type), TileInfo(DataType::Int32)),
+ _component_type(component_type)
+{
+}
+
+CLTensorComponent::CLTensorComponent(const CLTensorArgument &tensor, TensorComponentType component_type, int32_t value)
+ : CLTile({{std::to_string(value)}}, DataType::Int32), _component_type(component_type)
+{
+ CKW_UNUSED(tensor);
+}
+
+CLTensorComponent::~CLTensorComponent() = default;
+
+ITile &CLTensorComponent::tile()
+{
+ return *this;
+}
+
+const ITile &CLTensorComponent::tile() const
+{
+ return *this;
+}
+
+TensorComponentType CLTensorComponent::component_type() const
+{
+ return _component_type;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/CLTensorComponent.h b/compute_kernel_writer/src/cl/CLTensorComponent.h
new file mode 100644
index 0000000000..731597ebbf
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLTensorComponent.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_CL_CLTENSORCOMPONENT_H
+#define CKW_SRC_CL_CLTENSORCOMPONENT_H
+
+#include "ckw/types/TensorComponentType.h"
+
+#include "src/cl/CLTile.h"
+#include "src/ITensorComponent.h"
+
+namespace ckw
+{
+
+class CLTensorArgument;
+
+/** A tensor component object that can be used as a tile.
+ *
+ * The tensor component is created by @ref CLTensorArgument object when it is used
+ * either by the user or internally by a kernel writer operation.
+ * It allows the user to perform operation on tensor component just like any other tile.
+ *
+ * Because of the nature of tensor component, it's always a scalar tile of 32-bit integer.
+ *
+ * To find the list of all tensor components, see @ref TensorComponentType.
+ */
+class CLTensorComponent : public CLTile, public ITensorComponent
+{
+public:
+ /** Initialize a new instance of @ref CLTensorComponent class for dynamic component.
+ *
+ * @param[in] tensor The tensor to which this component belongs.
+ * @param[in] component_type The tensor component type.
+ */
+ CLTensorComponent(const CLTensorArgument &tensor, TensorComponentType component_type);
+
+ /** Initialize a new instance of @ref CLTensorComponent class for compile-time constant component.
+ *
+ * @param[in] tensor The tensor to which this component belongs.
+ * @param[in] component_type The tensor component type.
+ * @param[in] value The value of the component.
+ */
+ CLTensorComponent(const CLTensorArgument &tensor, TensorComponentType component_type, int32_t value);
+
+ /** Destructor. */
+ virtual ~CLTensorComponent();
+
+ ITile &tile() override;
+
+ const ITile &tile() const override;
+
+ TensorComponentType component_type() const override;
+
+private:
+ TensorComponentType _component_type{TensorComponentType::Unknown};
+};
+
+} // namespace ckw
+
+#endif // CKW_SRC_CL_CLTENSORCOMPONENT_H
diff --git a/compute_kernel_writer/src/cl/CLTile.cpp b/compute_kernel_writer/src/cl/CLTile.cpp
new file mode 100644
index 0000000000..f6e271e813
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLTile.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2023 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 "src/cl/CLTile.h"
+
+#include "ckw/Error.h"
+#include "ckw/TileInfo.h"
+
+#include "src/cl/CLHelpers.h"
+#include "src/Helpers.h"
+
+#include <algorithm>
+#include <vector>
+
+namespace ckw
+{
+CLTile::CLTile(const std::string &name, const TileInfo &info) : _is_constant(false)
+{
+ validate_tile_info(info);
+
+ _basename = name;
+ _info = info;
+}
+
+CLTile::CLTile(const TileContainer &vals, DataType dt) : _is_constant(true)
+{
+ const int32_t w = vals[0].size();
+ const int32_t h = vals.size();
+
+ _info.width(w);
+ _info.height(h);
+ _info.data_type(dt);
+
+ validate_tile_info(_info);
+
+ _vals = TileContainer(h, std::vector<std::string>(w));
+
+ for (int32_t y = 0; y < h; ++y)
+ {
+ for (int32_t x = 0; x < w; ++x)
+ {
+ _vals[y][x] = vals[y][x];
+ }
+ }
+}
+
+const std::string &CLTile::name() const
+{
+ return _basename;
+}
+
+const TileInfo &CLTile::info() const
+{
+ return _info;
+}
+
+TileVariable CLTile::scalar(int32_t row, int32_t col) const
+{
+ // Clamp to nearest valid edge
+ col = clamp(col, static_cast<int32_t>(0), _info.width() - 1);
+ row = clamp(row, static_cast<int32_t>(0), _info.height() - 1);
+
+ if (_is_constant)
+ {
+ // We can use the vector method to retrieve the scalar variable stored in the constant tile
+ return vector(row, col, 1);
+ }
+ else
+ {
+ TileVariable t;
+ t.str = create_var_name(row);
+ t.desc.dt = _info.data_type();
+ t.desc.len = 1;
+
+ // This check is required because if the width has only one element, we cannot use .s0
+ if (_info.width() != 1)
+ {
+ // Automatic broadcasting
+ t.str += ".s" + dec_to_hex_as_string(col);
+ }
+
+ return t;
+ }
+}
+
+TileVariable CLTile::vector(int32_t row) const
+{
+ // Clamp to nearest valid edge
+ row = clamp(row, static_cast<int32_t>(0), _info.height() - 1);
+
+ if (_is_constant)
+ {
+ return vector(row, 0, _info.width());
+ }
+ else
+ {
+ TileVariable t;
+ t.str = create_var_name(row);
+ t.desc.dt = _info.data_type();
+ t.desc.len = _info.width();
+ return t;
+ }
+}
+
+TileVariable CLTile::vector(int32_t row, int32_t col_start, int32_t width) const
+{
+ CKW_ASSERT(col_start >= 0 && col_start < _info.width());
+ CKW_ASSERT(col_start + width <= _info.width());
+
+ // Validate the new vector length
+ cl_validate_vector_length(width);
+
+ // Clamp to nearest valid edge
+ row = clamp(row, static_cast<int32_t>(0), _info.height() - 1);
+
+ TileVariable t;
+ t.desc.dt = _info.data_type();
+ t.desc.len = width;
+
+ if (_is_constant)
+ {
+ // The vector has the following form: ((data_typeN)(val0, val1,..., ValN-1))
+ t.str = "((" + cl_get_variable_datatype_as_string(t.desc.dt, width) + ")";
+ t.str += "(";
+
+ int32_t col = col_start;
+ for (; col < width - 1; ++col)
+ {
+ t.str += _vals[row][col];
+ t.str += ", ";
+ }
+ t.str += _vals[row][col];
+ t.str += "))";
+ }
+ else
+ {
+ t.str = create_var_name(row);
+
+ if (_info.width() != 1 && _info.width() != width)
+ {
+ t.str += ".s";
+ for (int i = 0; i < width; ++i)
+ {
+ t.str += dec_to_hex_as_string(col_start + i);
+ }
+ }
+ }
+
+ return t;
+}
+
+std::vector<TileVariable> CLTile::all() const
+{
+ std::vector<TileVariable> vars;
+
+ if (_is_constant)
+ {
+ for (int32_t y = 0; y < _info.height(); ++y)
+ {
+ for (int32_t x = 0; x < _info.width(); ++x)
+ {
+ // We can use the vector method to retrieve all the scalar variables stored in the constant tile
+ TileVariable t = vector(y, x, 1);
+ vars.push_back(t);
+ }
+ }
+ }
+ else
+ {
+ for (int32_t y = 0; y < _info.height(); ++y)
+ {
+ TileVariable t;
+ t.str = create_var_name(y);
+ t.desc.dt = _info.data_type();
+ t.desc.len = _info.width();
+ vars.push_back(t);
+ }
+ }
+
+ return vars;
+}
+
+bool CLTile::is_assignable() const
+{
+ return !_is_constant;
+}
+
+std::string CLTile::create_var_name(int32_t row) const
+{
+ std::string var_name = _basename;
+
+ // If a scalar variable, we do not append the row index
+ if (_info.height() > 1)
+ {
+ var_name += "__";
+ var_name += std::to_string(row);
+ }
+
+ return var_name;
+}
+
+std::vector<int32_t> CLTile::supported_vector_lengths() const
+{
+ return std::vector<int32_t>{1, 2, 3, 4, 8, 16};
+}
+
+void CLTile::validate_tile_info(const TileInfo &info) const
+{
+ CKW_UNUSED(info);
+ CKW_ASSERT_MSG(cl_validate_vector_length(info.width()), "Unsupported TileInfo width");
+ CKW_ASSERT_MSG(info.data_type() != DataType::Unknown, "DataType::Unknown is not supported");
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/CLTile.h b/compute_kernel_writer/src/cl/CLTile.h
new file mode 100644
index 0000000000..498cf51034
--- /dev/null
+++ b/compute_kernel_writer/src/cl/CLTile.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef COMPUTE_KERNEL_WRITER_SRC_CL_CLTILE_H
+#define COMPUTE_KERNEL_WRITER_SRC_CL_CLTILE_H
+
+#include "src/ITile.h"
+
+#include <string>
+
+namespace ckw
+{
+// Forward declarations
+class TileInfo;
+
+/** OpenCL specific tile */
+class CLTile : public ITile, public IVectorAccess
+{
+public:
+ /** Initialize a new instance of @ref CLTile class for variable tile.
+ *
+ * @param[in] name Tile name
+ * @param[in] info Tile info
+ */
+ CLTile(const std::string &name, const TileInfo &info);
+
+ /** Initialize a new instane of @ref CLTile class for compile-time constant tile.
+ *
+ * @note A constant tile does not need a name since this object does not return variable's name but rather
+ * values stored as string type
+ *
+ * @param[in] vals The tile container with the constant values as std::string
+ * @param[in] dt Datatype of the values stored in the tile container
+ */
+ CLTile(const TileContainer &vals, DataType dt);
+
+ // Inherited method overridden
+ const std::string &name() const override;
+
+ const TileInfo &info() const override;
+
+ TileVariable scalar(int32_t row, int32_t col) const override;
+
+ TileVariable vector(int32_t row) const override;
+
+ TileVariable vector(int32_t row, int32_t col_start, int32_t width) const override;
+
+ std::vector<TileVariable> all() const override;
+
+ bool is_assignable() const override;
+
+ std::vector<int32_t> supported_vector_lengths() const override;
+
+private:
+ void validate_tile_info(const TileInfo &info) const;
+
+ std::string create_var_name(int32_t row) const;
+
+ TileInfo _info{DataType::Unknown};
+ std::string _basename{""};
+ bool _is_constant{false};
+ TileContainer _vals{};
+};
+} // namespace ckw
+
+#endif /* COMPUTE_KERNEL_WRITER_SRC_CL_CLTILE_H */
diff --git a/compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.cpp b/compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.cpp
new file mode 100644
index 0000000000..7d16f35fbe
--- /dev/null
+++ b/compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2023 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 "src/cl/helpers/CLMemoryOpBufferHelper.h"
+
+#include "ckw/Error.h"
+#include "ckw/TensorSampler.h"
+#include "ckw/types/MemoryOperation.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include "src/cl/CLHelpers.h"
+#include "src/cl/CLKernelWriter.h"
+#include "src/cl/CLTensorArgument.h"
+#include "src/cl/CLTile.h"
+#include "src/ITensor.h"
+#include "src/Tensor3dMapper.h"
+#include "src/TileView.h"
+
+namespace ckw
+{
+bool CLMemoryOpBufferHelper::validate(const CLKernelWriter *writer,
+ const ITensor *tensor,
+ const TensorSampler *sampler,
+ const Tensor3dMapper *mapper,
+ MemoryOperation op,
+ const TileView<CLTile> &dst)
+{
+ CKW_UNUSED(writer, tensor, mapper, op, dst);
+
+ if (sampler->storage() != TensorStorageType::BufferUint8Ptr)
+ {
+ return false;
+ }
+ return true;
+}
+
+/** Initialization and Finalizing Logic
+ *
+ * The meanings of if/elses in different dimensions and how they're constructed:
+ * - x: partial load/store
+ * - y: no load/store operation
+ * - z: no load/store operation
+ * if(x)
+ * {
+ * if(z)
+ * {
+ * if(y)
+ * {
+ * // full load/store width
+ * }
+ * else
+ * {
+ * // no load/store
+ * }
+ * }
+ * else
+ * {
+ * // no load/store
+ * }
+ * }
+ * else
+ * {
+ * if(z)
+ * {
+ * if(y)
+ * {
+ * // partial load/store width
+ * }
+ * else
+ * {
+ * // no load/store
+ * }
+ * }
+ * else
+ * {
+ * // no load/store
+ * }
+ * }
+ *
+ * In general, initialize() writes if conditions, and finalize() writes else conditions.
+ * The outermost block is x, then z and then y. This is why, if/else's covering for y are initialized
+ * at each row write. In some addressing modes, such as None, no if/else conditions are written.
+ */
+void CLMemoryOpBufferHelper::initialize(const CLTile *x, const CLTile *z, const CLTile *b)
+{
+ CKW_ASSERT(validate(_writer, _tensor, _sampler, _mapper.get(), _op, _dst));
+
+ _coord_x = x->scalar(0, 0).str;
+ _coord_z = z->scalar(0, 0).str;
+ _coord_b = b->scalar(0, 0).str;
+ _coord_orig_z = _coord_z;
+
+ out_of_bound_initialize_x(_coord_x);
+ out_of_bound_initialize_z(_coord_z);
+}
+
+void CLMemoryOpBufferHelper::write_row(int32_t row_id, const std::string &coord_y)
+{
+ // The only check required is on Y.
+ out_of_bound_initialize_y(coord_y);
+
+ const std::string dst = _dst.vector(row_id).str;
+ const std::string address = to_buffer_address(_coord_x, coord_y, _coord_z, _coord_b);
+ const std::string ls_buf = to_statement(_op, _ls_width_full, dst, address);
+
+ _writer->op_write_raw_code(ls_buf);
+ _writer->op_write_raw_code(";\n");
+
+ out_of_bound_finalize_y(dst);
+
+ // The left over load/store will be written in the finalize stage
+ if (_ls_width_part.size() != 0)
+ {
+ int32_t col_start = 0;
+ const TileArea original_area = _dst.area();
+
+ for (int32_t partial_width : _ls_width_part)
+ {
+ // Set the active area
+ const TileArea area(original_area.row_start(), original_area.row_end(), col_start,
+ col_start + partial_width);
+ _dst.area(area);
+
+ const std::string dst = _dst.vector(row_id).str;
+ const std::string coord_x = _coord_x + " + " + std::to_string(col_start);
+ const std::string address = to_buffer_address(coord_x, coord_y, _coord_z, _coord_b);
+ const std::string statement = to_statement(_op, partial_width, dst, address);
+ _leftovers_x.emplace_back(dst, coord_y, statement);
+
+ col_start += partial_width;
+ }
+ // Restore the original area
+ _dst.area(original_area);
+ }
+}
+
+void CLMemoryOpBufferHelper::finalize()
+{
+ out_of_bound_finalize_z();
+ out_of_bound_finalize_x();
+}
+
+void CLMemoryOpBufferHelper::out_of_bound_initialize_x(const std::string &coord)
+{
+ if (_sampler->address_mode_x() == TensorSamplerAddressModeX::OverlappingMin)
+ {
+ TensorInfo tensor_info = _tensor->info();
+ TensorShape shape = tensor_info.shape();
+
+ _ls_width_part = cl_decompose_vector_width(shape[0] % _ls_width_full);
+ if (_ls_width_part.size() != 0)
+ {
+ _writer->op_write_raw_code("if(" + coord + " > 0)\n{\n");
+ }
+ }
+}
+
+void CLMemoryOpBufferHelper::out_of_bound_finalize_x()
+{
+ if (_sampler->address_mode_x() == TensorSamplerAddressModeX::OverlappingMin)
+ {
+ if (_ls_width_part.size() != 0)
+ {
+ _writer->op_write_raw_code("}\nelse\n{\n");
+
+ out_of_bound_initialize_z(_coord_orig_z);
+ for (LeftoverDescriptor leftover_desc : _leftovers_x)
+ {
+ out_of_bound_initialize_y(leftover_desc.coord);
+ _writer->op_write_raw_code(leftover_desc.statement);
+ _writer->op_write_raw_code(";\n");
+ out_of_bound_finalize_y(leftover_desc.dst);
+ }
+ out_of_bound_finalize_z();
+ _writer->op_write_raw_code("}\n");
+ }
+ }
+}
+
+void CLMemoryOpBufferHelper::out_of_bound_initialize_y(const std::string &coord)
+{
+ std::string max = "";
+
+ const TensorSamplerAddressModeY address_mode_y = _sampler->address_mode_y();
+
+ switch (address_mode_y)
+ {
+ case TensorSamplerAddressModeY::ClampToBorderMaxOnly:
+ // Not to be moved outside the case because it marks the relevant tensor component as used even if we dont't use the variable
+ max = _mapper->dim_y().str;
+ _writer->op_write_raw_code("if(" + coord + " < " + max + ")\n{\n");
+ break;
+ case TensorSamplerAddressModeY::SkipLessThanZero:
+ _writer->op_write_raw_code("if(" + coord + " >= 0)\n{\n");
+ break;
+ case TensorSamplerAddressModeY::None:
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported address mode for Y dimension");
+ }
+}
+
+void CLMemoryOpBufferHelper::out_of_bound_finalize_y(const std::string &dst)
+{
+ const TensorSamplerAddressModeY address_mode_y = _sampler->address_mode_y();
+
+ switch (address_mode_y)
+ {
+ case TensorSamplerAddressModeY::ClampToBorderMaxOnly:
+ _writer->op_write_raw_code("}\nelse\n{\n");
+ _writer->op_write_raw_code(dst);
+ _writer->op_write_raw_code(" = 0.0f;\n}\n");
+ break;
+ case TensorSamplerAddressModeY::SkipLessThanZero:
+ _writer->op_write_raw_code("}\n");
+ break;
+ case TensorSamplerAddressModeY::None:
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported address mode for Y dimension");
+ }
+}
+
+void CLMemoryOpBufferHelper::out_of_bound_initialize_z(const std::string &coord)
+{
+ CKW_UNUSED(coord);
+
+ const TensorSamplerAddressModeZ address_mode_z = _sampler->address_mode_z();
+ switch (address_mode_z)
+ {
+ case TensorSamplerAddressModeZ::None:
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported address mode for Z dimension");
+ }
+}
+
+void CLMemoryOpBufferHelper::out_of_bound_finalize_z()
+{
+ const TensorSamplerAddressModeZ address_mode_z = _sampler->address_mode_z();
+
+ switch (address_mode_z)
+ {
+ case TensorSamplerAddressModeZ::None:
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported address mode for Z dimension");
+ }
+}
+
+std::string CLMemoryOpBufferHelper::to_statement(MemoryOperation op,
+ int32_t vector_width,
+ const std::string &data,
+ const std::string &address) const
+{
+ switch (op)
+ {
+ case MemoryOperation::Load:
+ if (vector_width != 1)
+ {
+ return data + " = vload" + std::to_string(vector_width) + "(0, " + address + ")";
+ }
+ else
+ {
+ return data + " = *(" + address + ")";
+ }
+ break;
+ case MemoryOperation::Store:
+ if (vector_width != 1)
+ {
+ return "vstore" + std::to_string(vector_width) + "(" + data + ", 0, " + address + ")";
+ }
+ else
+ {
+ return "*(" + address + ") = " + data;
+ }
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported MemoryOperation");
+ }
+
+ return "";
+}
+
+std::string CLMemoryOpBufferHelper::to_buffer_address(const std::string &x,
+ const std::string &y,
+ const std::string &z,
+ const std::string &b) const
+{
+ TensorStorageType tensor_storage = _sampler->storage();
+ CKW_ASSERT(tensor_storage == TensorStorageType::BufferUint8Ptr);
+
+ const std::string ptr_buf = _tensor->storage(tensor_storage).val;
+ const std::string dst_type = cl_data_type_rounded_up_to_valid_vector_width(_dst.data_type(), 1);
+
+ std::string address;
+ address += "(__global ";
+ address += dst_type;
+ address += "*)(";
+ address += ptr_buf;
+ if (x != "0" && (_mapper->dim_x().str != "1"))
+ {
+ address += " + (";
+ address += x + ") * sizeof(" + dst_type + ")";
+ }
+ if (y != "0")
+ {
+ const std::string stride_y = _mapper->stride_y().str;
+ address += " + (";
+ address += y + ")";
+ address += " * ";
+ address += stride_y;
+ }
+ if (z != "0" && (_mapper->dim_z().str != "1"))
+ {
+ const std::string stride_z = _mapper->stride_z().str;
+ address += " + (";
+ address += z + ")";
+ address += " * ";
+ address += stride_z;
+ }
+ if (b != "0" && (_mapper->dim_batch().str != "1"))
+ {
+ const std::string stride_b = _mapper->stride_batch().str;
+ address += " + (";
+ address += b + ")";
+ address += " * ";
+ address += stride_b;
+ }
+ address += ")";
+ return address;
+}
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.h b/compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.h
new file mode 100644
index 0000000000..a6b3272f32
--- /dev/null
+++ b/compute_kernel_writer/src/cl/helpers/CLMemoryOpBufferHelper.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_CL_HELPERS_CLMEMORYOPBUFFERHELPER_H
+#define CKW_SRC_CL_HELPERS_CLMEMORYOPBUFFERHELPER_H
+
+#include "src/cl/helpers/ICLMemoryOpHelper.h"
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+
+// Forward Declarations
+class CLKernelWriter;
+class CLTile;
+template <class CLTile>
+class TileView;
+enum class MemoryOperation;
+
+/** Helper class to write memory operations (like load/store) in OpenCL
+ */
+class CLMemoryOpBufferHelper : public ICLMemoryOpHelper
+{
+public:
+ /** Constructor similar to @ref ICLMemoryOpHelper() */
+ CLMemoryOpBufferHelper(CLKernelWriter *writer,
+ ITensor *tensor,
+ TensorSampler *sampler,
+ MemoryOperation op,
+ const TileView<CLTile> &dst)
+ : ICLMemoryOpHelper(writer, tensor, sampler, op, dst)
+ {
+ }
+
+ /** Copy constructor */
+ CLMemoryOpBufferHelper(const CLMemoryOpBufferHelper &) = delete;
+
+ /** Assignment operator overload */
+ CLMemoryOpBufferHelper &operator=(const CLMemoryOpBufferHelper &) = delete;
+
+ // Methods overridden
+ void initialize(const CLTile *x, const CLTile *z, const CLTile *b) override;
+ void write_row(int32_t row_id, const std::string &coord_y) override;
+ void finalize() override;
+
+private:
+ struct LeftoverDescriptor
+ {
+ LeftoverDescriptor(const std::string &dst, const std::string &coord, const std::string &statement)
+ : dst(dst), coord(coord), statement(statement)
+ {
+ }
+
+ std::string dst{}; // Describes the destination tile or part of it
+ std::string coord{}; // Describes the coordinate to be used in boundary checks
+ std::string statement{}; // Describes the memory operation statement
+ };
+
+ std::vector<int32_t> _ls_width_part{};
+ std::vector<LeftoverDescriptor> _leftovers_x{};
+ std::string _coord_orig_z{};
+
+ static bool validate(const CLKernelWriter *writer,
+ const ITensor *tensor,
+ const TensorSampler *sampler,
+ const Tensor3dMapper *mapper,
+ MemoryOperation op,
+ const TileView<CLTile> &dst);
+
+ void out_of_bound_initialize_x(const std::string &coord);
+ void out_of_bound_finalize_x();
+ void out_of_bound_initialize_y(const std::string &coord);
+ void out_of_bound_finalize_y(const std::string &dst);
+ void out_of_bound_initialize_z(const std::string &coord);
+ void out_of_bound_finalize_z();
+
+ std::string
+ to_statement(MemoryOperation op, int32_t vector_width, const std::string &data, const std::string &address) const;
+ std::string
+ to_buffer_address(const std::string &x, const std::string &y, const std::string &z, const std::string &b) const;
+};
+} // namespace ckw
+
+#endif // CKW_SRC_CL_HELPERS_CLMEMORYOPBUFFERHELPER_H
diff --git a/compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.cpp b/compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.cpp
new file mode 100644
index 0000000000..f392cd89cc
--- /dev/null
+++ b/compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2023 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 "src/cl/helpers/CLMemoryOpImage2dHelper.h"
+
+#include "ckw/Error.h"
+#include "ckw/TensorSampler.h"
+#include "ckw/types/MemoryOperation.h"
+#include "ckw/types/TensorStorageType.h"
+
+#include "src/cl/CLKernelWriter.h"
+#include "src/cl/CLTensorArgument.h"
+#include "src/cl/CLTile.h"
+#include "src/ITensor.h"
+#include "src/Tensor3dMapper.h"
+#include "src/TileView.h"
+
+namespace ckw
+{
+void CLMemoryOpImage2dHelper::initialize(const CLTile *x, const CLTile *z, const CLTile *b)
+{
+ _coord_x = x->scalar(0, 0).str;
+ _coord_z = z->scalar(0, 0).str;
+ _coord_b = b->scalar(0, 0).str;
+}
+
+void CLMemoryOpImage2dHelper::write_row(int32_t row_id, const std::string &coord_y)
+{
+ // The only check required is on Y.
+ out_of_bound_initialize_y(coord_y);
+
+ const std::string dst = _dst.vector(row_id).str;
+ const std::string sampler = to_ls_image2d_sampler();
+ const std::string coord = to_ls_image2d_address(_coord_x, coord_y, _coord_z, _coord_b);
+ const std::string ls_buf = to_ls_image2d(_op, _ls_width_full, dst, sampler, coord);
+
+ _writer->op_write_raw_code(ls_buf + ";\n");
+
+ out_of_bound_finalize_y();
+}
+
+void CLMemoryOpImage2dHelper::finalize()
+{
+}
+
+bool CLMemoryOpImage2dHelper::validate(const CLKernelWriter *writer,
+ const ITensor *tensor,
+ const TensorSampler *sampler,
+ const Tensor3dMapper *mapper,
+ MemoryOperation op,
+ const TileView<CLTile> &dst)
+{
+ CKW_UNUSED(writer, tensor, mapper);
+
+ if (dst.width() != 4)
+ {
+ return false;
+ }
+ if (sampler->address_mode_x() != TensorSamplerAddressModeX::None)
+ {
+ return false;
+ }
+ if (sampler->address_mode_z() != TensorSamplerAddressModeZ::None)
+ {
+ return false;
+ }
+ if (sampler->storage() != TensorStorageType::Texture2dReadOnly && op == MemoryOperation::Load)
+ {
+ return false;
+ }
+ if (sampler->storage() != TensorStorageType::Texture2dWriteOnly && op == MemoryOperation::Store)
+ {
+ return false;
+ }
+ if ((dst.data_type() != DataType::Fp32) && (dst.data_type() != DataType::Fp16))
+ {
+ return false;
+ }
+ return true;
+}
+
+void CLMemoryOpImage2dHelper::out_of_bound_initialize_y(const std::string &coord)
+{
+ CKW_UNUSED(coord);
+
+ const TensorSamplerAddressModeY address_mode_y = _sampler->address_mode_y();
+ switch (address_mode_y)
+ {
+ case TensorSamplerAddressModeY::SkipLessThanZero:
+ _writer->op_write_raw_code("if(" + coord + " >= 0)\n{\n");
+ break;
+ case TensorSamplerAddressModeY::ClampToBorderMaxOnly:
+ case TensorSamplerAddressModeY::None:
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported address mode for Y dimension");
+ }
+}
+
+void CLMemoryOpImage2dHelper::out_of_bound_finalize_y()
+{
+ const TensorSamplerAddressModeY address_mode_y = _sampler->address_mode_y();
+ switch (address_mode_y)
+ {
+ case TensorSamplerAddressModeY::SkipLessThanZero:
+ _writer->op_write_raw_code("}\n");
+ break;
+ case TensorSamplerAddressModeY::ClampToBorderMaxOnly:
+ case TensorSamplerAddressModeY::None:
+ break;
+ default:
+ CKW_THROW_MSG("Unsupported address mode for Y dimension");
+ }
+}
+
+std::string CLMemoryOpImage2dHelper::to_ls_image2d(MemoryOperation op,
+ int32_t vector_width,
+ const std::string &data,
+ const std::string &sampler,
+ const std::string &address) const
+{
+ CKW_UNUSED(vector_width);
+ CKW_ASSERT_MSG(_dst.data_type() == DataType::Fp32 || _dst.data_type() == DataType::Fp16,
+ "Image2d only supports floating-point data type");
+
+ const TensorStorageType tensor_storage = _sampler->storage();
+ const std::string image2d_obj = _tensor->storage(tensor_storage).val;
+ const std::string post_fix = _dst.data_type() == DataType::Fp32 ? "f" : "h";
+
+ switch (op)
+ {
+ case MemoryOperation::Load:
+ return data + " = read_image" + post_fix + "(" + image2d_obj + ", " + sampler + ", " + address + ")";
+ break;
+ case MemoryOperation::Store:
+ return "write_image" + post_fix + "(" + image2d_obj + ", " + address + ", " + data + ")";
+ default:
+ CKW_THROW_MSG("Unsupported MemoryOperation");
+ }
+}
+
+std::string CLMemoryOpImage2dHelper::to_ls_image2d_sampler() const
+{
+ const auto address_mode_y = _sampler->address_mode_y();
+
+ switch (address_mode_y)
+ {
+ case TensorSamplerAddressModeY::None:
+ return "CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST";
+ case TensorSamplerAddressModeY::SkipLessThanZero:
+ case TensorSamplerAddressModeY::ClampToBorderMaxOnly:
+ return "CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST";
+ default:
+ CKW_THROW_MSG("Unsupported address_mode_coord");
+ }
+}
+
+std::string CLMemoryOpImage2dHelper::to_ls_image2d_address(const std::string &x,
+ const std::string &y,
+ const std::string &z,
+ const std::string &b) const
+{
+ std::string coord_x = "(" + x + ") >> 2";
+ std::string coord_y = "(";
+
+ if (y != "0")
+ {
+ coord_y += y;
+ }
+ if (z != "0" && (_mapper->dim_z().str != "1"))
+ {
+ const std::string dim = _mapper->dim_y().str;
+ coord_y += " + (";
+ coord_y += z + ")";
+ coord_y += " * ";
+ coord_y += dim;
+ }
+ if (b != "0" && (_mapper->dim_batch().str != "1"))
+ {
+ const std::string dim0 = _mapper->dim_y().str;
+ const std::string dim1 = _mapper->dim_z().str;
+ coord_y += " + (";
+ coord_y += b + ")";
+ coord_y += " * ";
+ coord_y += dim0;
+ coord_y += " * ";
+ coord_y += dim1;
+ }
+ coord_y += ")";
+ return "(int2)(" + coord_x + ", " + coord_y + ")";
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.h b/compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.h
new file mode 100644
index 0000000000..6c42c132d9
--- /dev/null
+++ b/compute_kernel_writer/src/cl/helpers/CLMemoryOpImage2dHelper.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_CL_HELPERS_CLMEMORYOPIMAGE2DHELPER_H
+#define CKW_SRC_CL_HELPERS_CLMEMORYOPIMAGE2DHELPER_H
+
+#include "src/cl/helpers/ICLMemoryOpHelper.h"
+
+#include <string>
+
+namespace ckw
+{
+
+// Forward Declarations
+class CLKernelWriter;
+class CLTile;
+template <class CLTile>
+class TileView;
+enum class MemoryOperation;
+
+/** Helper class to write memory operations (like load/store) in OpenCL for Image2d type */
+class CLMemoryOpImage2dHelper : public ICLMemoryOpHelper
+{
+public:
+ /** Constructor similar to @ref ICLMemoryOpHelper() */
+ CLMemoryOpImage2dHelper(CLKernelWriter *writer,
+ ITensor *tensor,
+ TensorSampler *sampler,
+ MemoryOperation op,
+ const TileView<CLTile> &dst)
+ : ICLMemoryOpHelper(writer, tensor, sampler, op, dst)
+ {
+ }
+
+ /** Copy constructor */
+ CLMemoryOpImage2dHelper(const CLMemoryOpImage2dHelper &) = delete;
+
+ /** Assignment operator overload */
+ CLMemoryOpImage2dHelper &operator=(const CLMemoryOpImage2dHelper &) = delete;
+
+ // Methods overridden
+ void initialize(const CLTile *x, const CLTile *z, const CLTile *b) override;
+ void write_row(int32_t row_id, const std::string &coord_y) override;
+ void finalize() override;
+
+private:
+ static bool validate(const CLKernelWriter *writer,
+ const ITensor *tensor,
+ const TensorSampler *sampler,
+ const Tensor3dMapper *mapper,
+ MemoryOperation op,
+ const TileView<CLTile> &dst);
+
+ void out_of_bound_initialize_y(const std::string &coord);
+ void out_of_bound_finalize_y();
+
+ std::string to_ls_image2d(MemoryOperation op,
+ int32_t vector_width,
+ const std::string &data,
+ const std::string &sampler,
+ const std::string &address) const;
+ std::string to_ls_image2d_sampler() const;
+ std::string
+ to_ls_image2d_address(const std::string &x, const std::string &y, const std::string &z, const std::string &b) const;
+};
+} // namespace ckw
+
+#endif // CKW_SRC_CL_HELPERS_CLMEMORYOPIMAGE2DHELPER_H
diff --git a/compute_kernel_writer/src/cl/helpers/ICLMemoryOpHelper.h b/compute_kernel_writer/src/cl/helpers/ICLMemoryOpHelper.h
new file mode 100644
index 0000000000..a5b679ac03
--- /dev/null
+++ b/compute_kernel_writer/src/cl/helpers/ICLMemoryOpHelper.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_CL_HELPERS_ICLMEMORYOPHELPER_H
+#define CKW_SRC_CL_HELPERS_ICLMEMORYOPHELPER_H
+
+#include "ckw/TensorSampler.h"
+
+#include "src/Tensor3dMapper.h"
+#include "src/TileView.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+namespace ckw
+{
+
+// Forward Declarations
+class CLTile;
+class CLKernelWriter;
+class ITensor;
+class TensorSampler;
+enum class MemoryOperation;
+
+/** Base class OpenCL memory operation helper classes
+ * that helps writing code for memory operations like load/store.
+ */
+class ICLMemoryOpHelper
+{
+public:
+ /** Constructor
+ *
+ * @param[in] writer @ref ckw::CLKernelWriter object to write the code
+ * @param[in] tensor @ref ckw::ITensor object to perform the memory operation on
+ * @param[in] sampler @ref ckw::TensorSampler object that tells how to sample a tensor
+ * @param[in] op The memory operation to be done (e.g. Load/Store)
+ * @param[in] dst The tile to perform the memory operation on
+ */
+ ICLMemoryOpHelper(CLKernelWriter *writer,
+ ITensor *tensor,
+ TensorSampler *sampler,
+ MemoryOperation op,
+ const TileView<CLTile> &dst)
+ : _writer(writer), _tensor(tensor), _sampler(sampler), _op(op), _dst(dst)
+ {
+ _mapper = std::make_unique<Tensor3dMapper>(tensor, sampler->format());
+ _ls_width_full = _dst.width();
+ }
+
+ /** Copy constructor */
+ ICLMemoryOpHelper(const ICLMemoryOpHelper &) = delete;
+
+ /** Assignment operator overload */
+ ICLMemoryOpHelper &operator=(const ICLMemoryOpHelper &) = delete;
+
+ /** Destructor */
+ virtual ~ICLMemoryOpHelper() = default;
+
+ /** Initialization method that takes a 3D tensor's x, z dimensions and
+ * the batch offset as a tile object, and initializes the code inside
+ * the writer object.
+ *
+ * @param[in] x tile object that describes the x-coordinate of the tensor involved
+ * @param[in] z tile object that describes the z-coordinate of the tensor involved
+ * @param[in] b tile object that describes the batch offset of the tensor involved
+ */
+ virtual void initialize(const CLTile *x, const CLTile *z, const CLTile *b) = 0;
+
+ /** Method that writes the actual code to the writer that performs the mentioned memory
+ * operation on the tile initialized. It writes the code for a specific row given in the
+ * arguments.
+ *
+ * @param[in] row_id row id
+ * @param[in] coord_y y-coordinate as string
+ */
+ virtual void write_row(int32_t row_id, const std::string &coord_y) = 0;
+
+ /** Method that finalizes the code in the writer object. This part is usually for taking
+ * care of finalizing anything that's been initialized inside @ref IMemoryHelper::initialize()
+ * such as matching compound statements, checking certain boundary conditions etc. No inputs
+ * and/or outputs, only the writer object is affected.
+ */
+ virtual void finalize() = 0;
+
+protected:
+ CLKernelWriter *_writer{nullptr};
+ ITensor *_tensor{nullptr};
+ TensorSampler *_sampler{nullptr};
+ MemoryOperation _op;
+ std::unique_ptr<Tensor3dMapper> _mapper{nullptr};
+ TileView<CLTile> _dst{};
+ int32_t _ls_width_full{0};
+ std::string _coord_x{};
+ std::string _coord_z{};
+ std::string _coord_b{};
+};
+} // namespace ckw
+
+#endif // CKW_SRC_CL_HELPERS_ICLMEMORYOPHELPER_H
diff --git a/compute_kernel_writer/src/types/ConstantData.cpp b/compute_kernel_writer/src/types/ConstantData.cpp
new file mode 100644
index 0000000000..6d15eab407
--- /dev/null
+++ b/compute_kernel_writer/src/types/ConstantData.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2023 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 "ckw/types/ConstantData.h"
+
+#include <limits>
+
+namespace ckw
+{
+namespace
+{
+template <typename T>
+typename std::enable_if<std::is_same<T, float>::value, std::string>::type to_str(T value)
+{
+ std::stringstream ss;
+ ss << std::scientific << std::setprecision(std::numeric_limits<T>::max_digits10) << value;
+ return ss.str();
+}
+
+template <typename T>
+typename std::enable_if<!std::is_same<T, float>::value && !std::is_same<T, bool>::value, std::string>::type
+to_str(T value)
+{
+ return std::to_string(value);
+}
+
+template <typename T>
+typename std::enable_if<std::is_same<T, bool>::value, std::string>::type to_str(T value)
+{
+ return std::to_string((int)value);
+}
+} // namespace
+
+template <typename T>
+ConstantData::ConstantData(std::initializer_list<std::initializer_list<T>> values, DataType data_type)
+ : _data_type(data_type)
+{
+ CKW_ASSERT(validate<T>(data_type));
+ CKW_ASSERT(values.size() > 0);
+
+ for (auto value_arr : values)
+ {
+ // Each row must have the same number of elements
+ CKW_ASSERT(value_arr.size() == (*values.begin()).size());
+
+ StringVector vec;
+ std::transform(value_arr.begin(), value_arr.end(), std::back_inserter(vec), [](T val) { return to_str(val); });
+
+ _values.push_back(std::move(vec));
+ }
+}
+
+template <typename T>
+ConstantData::ConstantData(const std::vector<std::vector<T>> &values, DataType data_type) : _data_type(data_type)
+{
+ CKW_ASSERT(validate<T>(data_type));
+ CKW_ASSERT(values.size() > 0);
+
+ for (auto value_arr : values)
+ {
+ // Each row must have the same number of elements
+ CKW_ASSERT(value_arr.size() == (*values.begin()).size());
+
+ StringVector vec;
+ std::transform(value_arr.begin(), value_arr.end(), std::back_inserter(vec), [](T val) { return to_str(val); });
+
+ _values.push_back(std::move(vec));
+ }
+}
+
+template <typename T>
+bool ConstantData::validate(DataType data_type)
+{
+ switch (data_type)
+ {
+ case DataType::Fp32:
+ case DataType::Fp16:
+ return std::is_same<T, float>::value;
+ case DataType::Bool:
+ return std::is_same<T, bool>::value;
+ case DataType::Int32:
+ case DataType::Int16:
+ case DataType::Int8:
+ return std::is_same<T, int32_t>::value;
+ case DataType::Uint32:
+ case DataType::Uint16:
+ case DataType::Uint8:
+ return std::is_same<T, uint32_t>::value;
+ default:
+ CKW_THROW_MSG("Unknown data type!");
+ break;
+ }
+}
+
+// Necessary instantiations for compiler to recognize
+template ConstantData::ConstantData(std::initializer_list<std::initializer_list<int32_t>>, DataType);
+template ConstantData::ConstantData(std::initializer_list<std::initializer_list<uint32_t>>, DataType);
+template ConstantData::ConstantData(std::initializer_list<std::initializer_list<bool>>, DataType);
+template ConstantData::ConstantData(std::initializer_list<std::initializer_list<float>>, DataType);
+template ConstantData::ConstantData(const std::vector<std::vector<int32_t>> &, DataType);
+template ConstantData::ConstantData(const std::vector<std::vector<uint32_t>> &, DataType);
+template ConstantData::ConstantData(const std::vector<std::vector<bool>> &, DataType);
+template ConstantData::ConstantData(const std::vector<std::vector<float>> &, DataType);
+
+template bool ConstantData::validate<int32_t>(DataType);
+template bool ConstantData::validate<uint32_t>(DataType);
+template bool ConstantData::validate<bool>(DataType);
+template bool ConstantData::validate<float>(DataType);
+
+const std::vector<std::vector<std::string>> &ConstantData::values() const
+{
+ return _values;
+}
+
+DataType ConstantData::data_type() const
+{
+ return _data_type;
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/types/DataTypeHelpers.cpp b/compute_kernel_writer/src/types/DataTypeHelpers.cpp
new file mode 100644
index 0000000000..7f0c33fb72
--- /dev/null
+++ b/compute_kernel_writer/src/types/DataTypeHelpers.cpp
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2023 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 "src/types/DataTypeHelpers.h"
+
+namespace ckw
+{
+
+bool is_data_type_float(DataType data_type)
+{
+ return (data_type == DataType::Fp32 || data_type == DataType::Fp16);
+}
+
+} // namespace ckw
diff --git a/compute_kernel_writer/src/types/DataTypeHelpers.h b/compute_kernel_writer/src/types/DataTypeHelpers.h
new file mode 100644
index 0000000000..b6ec6ccd19
--- /dev/null
+++ b/compute_kernel_writer/src/types/DataTypeHelpers.h
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2023 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.
+*/
+
+#ifndef CKW_SRC_TYPES_DATATYPEHELPERS_H
+#define CKW_SRC_TYPES_DATATYPEHELPERS_H
+
+#include "ckw/types/DataType.h"
+
+namespace ckw
+{
+
+/** Return a value indicating whether the data type is floating-point.
+ *
+ * @param[in] data_type The data type to check.
+ *
+ * @return Whether the data type is floating-point.
+ */
+bool is_data_type_float(DataType data_type);
+
+} // namespace ckw
+
+#endif // CKW_SRC_TYPES_DATATYPEHELPERS_H
diff --git a/compute_kernel_writer/src/types/TensorComponentType.h b/compute_kernel_writer/src/types/TensorComponentType.h
new file mode 100644
index 0000000000..03f4f4f5c8
--- /dev/null
+++ b/compute_kernel_writer/src/types/TensorComponentType.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_SRC_TYPES_TENSORCOMPONENTTYPE_H
+#define CKW_SRC_TYPES_TENSORCOMPONENTTYPE_H
+
+#include <cstdint>
+
+namespace ckw
+{
+
+/** Compute Kernel Writer tensor component bitmask.
+ *
+ * The bitmask can be used to retrieve the info from @ref TensorComponent.
+ */
+enum class TensorComponentBitmask : uint32_t
+{
+ OffsetFirstElement = 0x01000000, // For example, OffsetFirstElement in TensorComponent
+ Stride = 0x02000000, // For example, stride0 in TensorComponent
+ Dimension = 0x04000000, // For example, Dim0 in TensorComponent
+ FoldedDimensions = 0x08000000, // For example, Dim0xDim1 in TensorComponent
+};
+
+/** Mask to retrieve the component index (for example, 1 for stride1, 2 for stride2, or 1 and 2 for Dim1xDim2).
+ *
+ * The 4 least significant half-bytes (nibbles) of the @ref TensorComponent are used to retrieve the specific component index.
+ * TensorComponent = | i7 | i6 | i5 | i4 | i3 | i2 | i1 | i0 |, where i7,...i0 are the nibbles
+ * of the TensorComponent hexadecimal number. i0, i1, i2 and i3 are reserved to the component index.
+ *
+ * In particular:
+ *
+ * -# i0: reserved to the first folded dimension component index
+ * -# i1: reserved to the second folded dimension component index
+ * -# i2: reserved to the third folded dimension component index
+ * -# i3: reserved to the fourth folded dimension component index
+ *
+ * Therefore, if there are no folded dimensions (dimensions and strides), only i0 is used.
+ * Instead, if there are two folded dimensions, only i0 and i1 are used.
+ *
+ * The component index is stored with the corresponding hexadecimal number + 1,
+ * hence the component index 0 is represented as 1, while the component index 3 is represented as 4.
+ */
+enum class TensorComponentIndexBitmask : uint32_t
+{
+ All = 0x0000ffff, // All nibbles reserved to the tensor component index
+ Index0 = 0x0000000f, // Folded dimension 0
+ Index1 = 0x000000f0, // Folded dimension 1
+ Index2 = 0x00000f00, // Folded dimension 2
+ Index3 = 0x0000f000 // Folded dimension 3
+};
+
+/** The maximum number of folded dimensions. */
+constexpr int tensor_component_index_max_count = 4;
+
+} // namespace ckw
+
+#endif // CKW_SRC_TYPES_TENSORCOMPONENTTYPE_H
diff --git a/compute_kernel_writer/validation/Validation.cpp b/compute_kernel_writer/validation/Validation.cpp
new file mode 100644
index 0000000000..4fbd1eacda
--- /dev/null
+++ b/compute_kernel_writer/validation/Validation.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2023 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 "validation/tests/CLConstantTileTest.hpp"
+#include "validation/tests/CLKernelWriterAssignTest.h"
+#include "validation/tests/CLKernelWriterBinaryOpTest.h"
+#include "validation/tests/CLKernelWriterCastTest.h"
+#include "validation/tests/CLKernelWriterCommentTest.h"
+#include "validation/tests/CLKernelWriterDeclareConstantTileTest.h"
+#include "validation/tests/CLKernelWriterDeclareTensorTest.h"
+#include "validation/tests/CLKernelWriterDeclareTileTest.h"
+#include "validation/tests/CLKernelWriterForTest.h"
+#include "validation/tests/CLKernelWriterGetGlobalIdTest.h"
+#include "validation/tests/CLKernelWriterIfTest.h"
+#include "validation/tests/CLKernelWriterOpLoadIndirectTest.h"
+#include "validation/tests/CLKernelWriterOpLoadStoreTest.h"
+#include "validation/tests/CLKernelWriterPrintTest.h"
+#include "validation/tests/CLKernelWriterReturnTest.h"
+#include "validation/tests/CLKernelWriterSubTileTest.h"
+#include "validation/tests/CLKernelWriterTernaryOpTest.h"
+#include "validation/tests/CLKernelWriterUnaryExpressionTest.h"
+#include "validation/tests/CLTensorArgumentTest.h"
+#include "validation/tests/CLTileTest.hpp"
+#include "validation/tests/TensorBitMaskTest.h"
+#include "validation/tests/UtilsTest.h"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+using namespace ckw;
+
+/** Main test program
+ */
+int32_t main()
+{
+ std::vector<ITest *> tests;
+
+ // Add your test here
+ const auto test0 = std::make_unique<UtilsTest>();
+ const auto test1 = std::make_unique<TensorBitMaskTrueTest>();
+ const auto test2 = std::make_unique<TensorBitMaskFalseTest>();
+ tests.push_back(test0.get());
+ tests.push_back(test1.get());
+ tests.push_back(test2.get());
+
+#ifdef COMPUTE_KERNEL_WRITER_OPENCL_ENABLED
+ const auto test3 = std::make_unique<CLTileInternalVariableNamesTest>();
+ const auto test4 = std::make_unique<CLTileInternalNumVariablesTest>();
+ const auto test5 = std::make_unique<CLTileAccessScalarVariableTest>();
+ const auto test6 = std::make_unique<CLTileAccessScalarVariableBroadcastXTest>();
+ const auto test7 = std::make_unique<CLTileAccessScalarVariableBroadcastYTest>();
+ const auto test8 = std::make_unique<CLTileAccessVectorVariablesTest>();
+ const auto test9 = std::make_unique<CLTileAccessSubVectorVariablesTest>();
+ const auto test10 = std::make_unique<CLConstantTileInternalValuesTest>();
+ const auto test11 = std::make_unique<CLConstantTileAccessScalarVariableBroadcastXTest>();
+ const auto test12 = std::make_unique<CLConstantTileAccessScalarVariableBroadcastYTest>();
+ const auto test13 = std::make_unique<CLConstantTileAccessVectorVariablesTest>();
+ const auto test14 = std::make_unique<CLConstantTileAccessSubVectorVariablesTest>();
+#ifdef COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+ const auto test15 = std::make_unique<CLKernelWriterCommentTest>();
+#endif /* COMPUTE_KERNEL_WRITER_DEBUG_ENABLED */
+ const auto test16 = std::make_unique<CLKernelWriterDeclareTileTest>();
+ const auto test17 = std::make_unique<CLTensorArgumentComponentNamesTest>();
+ const auto test18 = std::make_unique<CLTensorArgumentStorageNamesTest>();
+ const auto test19 = std::make_unique<CLTensorArgumentComponentValuesTest>();
+ const auto test20 = std::make_unique<CLTensorArgumentComponentsUsedPassByValueFalseTest>();
+ const auto test21 = std::make_unique<CLTensorArgumentComponentsUsedPassByValueTrueTest>();
+ const auto test22 = std::make_unique<CLTensorArgumentStoragesUsedTest>();
+ const auto test23 = std::make_unique<CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest>();
+ const auto test24 = std::make_unique<CLKernelWriterDeclareTensorTest>();
+ const auto test25 = std::make_unique<CLKernelWriterOpLoadStoreTest>();
+ const auto test26 = std::make_unique<CLKernelWriterAssignTest>();
+ const auto test27 = std::make_unique<CLKernelWriterCastTest>();
+ const auto test28 = std::make_unique<CLKernelWriterUnaryExpressionTest>();
+ const auto test29 = std::make_unique<CLKernelWriterBinaryOpTest>();
+ const auto test30 = std::make_unique<CLKernelWriterTernaryOpTest>();
+ const auto test31 = std::make_unique<CLKernelWriterDeclareConstantTileTest>();
+ const auto test32 = std::make_unique<CLKernelWriterIfTest>();
+ const auto test33 = std::make_unique<CLKernelWriterForTest>();
+ const auto test34 = std::make_unique<CLKernelWriterReturnTest>();
+ const auto test35 = std::make_unique<CLKernelWriterGetGlobalIdTest>();
+ const auto test36 = std::make_unique<CLKernelWriterPrintTest>();
+ const auto test37 = std::make_unique<CLKernelWriterOpLoadIndirectTest>();
+ const auto test38 = std::make_unique<CLKernelWriterSubTileTest>();
+
+ tests.push_back(test3.get());
+ tests.push_back(test4.get());
+ tests.push_back(test5.get());
+ tests.push_back(test6.get());
+ tests.push_back(test7.get());
+ tests.push_back(test8.get());
+ tests.push_back(test9.get());
+ tests.push_back(test10.get());
+ tests.push_back(test11.get());
+ tests.push_back(test12.get());
+ tests.push_back(test13.get());
+ tests.push_back(test14.get());
+#ifdef COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+ tests.push_back(test15.get());
+#endif /* COMPUTE_KERNEL_WRITER_DEBUG_ENABLED */
+ tests.push_back(test16.get());
+ tests.push_back(test17.get());
+ tests.push_back(test18.get());
+ tests.push_back(test19.get());
+ tests.push_back(test20.get());
+ tests.push_back(test21.get());
+ tests.push_back(test22.get());
+ tests.push_back(test23.get());
+ tests.push_back(test24.get());
+ tests.push_back(test25.get());
+ tests.push_back(test26.get());
+ tests.push_back(test27.get());
+ tests.push_back(test28.get());
+ tests.push_back(test29.get());
+ tests.push_back(test30.get());
+ tests.push_back(test31.get());
+ tests.push_back(test32.get());
+ tests.push_back(test33.get());
+ tests.push_back(test34.get());
+ tests.push_back(test35.get());
+ tests.push_back(test36.get());
+ tests.push_back(test37.get());
+ tests.push_back(test38.get());
+#endif /* COMPUTE_KERNEL_WRITER_OPENCL_ENABLED */
+
+ bool all_test_passed = true;
+
+ for(auto &x : tests)
+ {
+ std::cout << x->name() << std::endl;
+ all_test_passed &= x->run();
+ }
+
+ if(all_test_passed == true)
+ {
+ std::cout << "All tests passed" << std::endl;
+ }
+ else
+ {
+ throw std::runtime_error("One or more tests failed");
+ }
+
+ return 0;
+}
diff --git a/compute_kernel_writer/validation/tests/CLConstantTileTest.hpp b/compute_kernel_writer/validation/tests/CLConstantTileTest.hpp
new file mode 100644
index 0000000000..f10ad10146
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLConstantTileTest.hpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_TESTS_CLCONSTANTTILETEST_HPP
+#define CKW_TESTS_CLCONSTANTTILETEST_HPP
+
+#include "common/Common.h"
+#include "src/Helpers.h"
+#include "src/cl/CLHelpers.h"
+#include "src/cl/CLTile.h"
+
+#include <random>
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+class CLConstantTileInternalValuesTest : public ITest
+{
+public:
+ CLConstantTileInternalValuesTest()
+ {
+ _values.push_back({ { "1.2", "3.5" },
+ { "4.2", "1.3" } });
+ _values.push_back({ { "1.2" } });
+ _values.push_back({ { "1.2", "6.9" } });
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ int32_t test_idx = 0;
+ for(const auto &test : _values)
+ {
+ const CLTile tile(test, DataType::Fp16);
+ const auto vars = tile.all();
+ const int32_t num_vars = vars.size();
+ const int32_t width = tile.info().width();
+
+ for(int32_t y = 0; y < num_vars; ++y)
+ {
+ const int32_t col = y % width;
+ const int32_t row = y / width;
+ const std::string expected_var_name = "((half)(" + test[row][col] + "))";
+ const std::string actual_var_name = vars[y].str;
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLConstantTileInternalValuesTest";
+ }
+
+private:
+ std::vector<TileContainer> _values{};
+};
+
+class CLConstantTileAccessScalarVariableBroadcastXTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t height = 8;
+ const DataType dt = DataType::Fp16;
+
+ CLConstantTileAccessScalarVariableBroadcastXTest()
+ {
+ _width.push_back(1);
+ _width.push_back(2);
+ _width.push_back(3);
+
+ _x_coord.push_back(4);
+ _x_coord.push_back(5);
+ _x_coord.push_back(6);
+
+ _y_coord.push_back(1);
+ _y_coord.push_back(3);
+ _y_coord.push_back(2);
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_width.size() == _y_coord.size(), "The number of widths and y-coords does not match");
+ VALIDATE_ON_MSG(_x_coord.size() == _y_coord.size(), "The number of x-coords and y-coords does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const size_t num_coords = _x_coord.size();
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution<> dist(-1, 1);
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_coords; ++i)
+ {
+ const int32_t width = _width[i];
+ const int32_t x_coord = _x_coord[i];
+ const int32_t y_coord = _y_coord[i];
+
+ const int32_t x_coord_clamped = clamp(x_coord, static_cast<int32_t>(0), width - 1);
+
+ TileContainer container = TileContainer(height, std::vector<std::string>(width));
+
+ for(int32_t row = 0; row < height; ++row)
+ {
+ for(int32_t col = 0; col < width; ++col)
+ {
+ container[row][col] = std::to_string(dist(gen));
+ }
+ }
+
+ const CLTile tile(container, dt);
+
+ const TileVariable var = tile.scalar(y_coord, x_coord);
+
+ const std::string actual_var_name = var.str;
+ const std::string expected_var_name = "((half)(" + container[y_coord][x_coord_clamped] + "))";
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLConstantTileAccessScalarVariableBroadcastXTest";
+ }
+
+private:
+ std::vector<int32_t> _width{};
+ std::vector<int32_t> _x_coord{};
+ std::vector<int32_t> _y_coord{};
+};
+
+class CLConstantTileAccessScalarVariableBroadcastYTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t width = 8;
+ const DataType dt = DataType::Fp16;
+
+ CLConstantTileAccessScalarVariableBroadcastYTest()
+ {
+ _height.push_back(1);
+ _height.push_back(2);
+ _height.push_back(3);
+
+ _x_coord.push_back(4);
+ _x_coord.push_back(5);
+ _x_coord.push_back(6);
+
+ _y_coord.push_back(3);
+ _y_coord.push_back(4);
+ _y_coord.push_back(5);
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_height.size() == _y_coord.size(), "The number of widths and y-coords does not match");
+ VALIDATE_ON_MSG(_x_coord.size() == _y_coord.size(), "The number of x-coords and y-coords does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution<> dist(-1, 1);
+
+ const size_t num_coords = _x_coord.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_coords; ++i)
+ {
+ const int32_t height = _height[i];
+ const int32_t x_coord = _x_coord[i];
+ const int32_t y_coord = _y_coord[i];
+
+ const int32_t y_coord_clamped = clamp(y_coord, static_cast<int32_t>(0), height - 1);
+
+ TileContainer container = TileContainer(height, std::vector<std::string>(width));
+
+ for(int32_t row = 0; row < height; ++row)
+ {
+ for(int32_t col = 0; col < width; ++col)
+ {
+ container[row][col] = std::to_string(dist(gen));
+ }
+ }
+
+ const CLTile tile(container, dt);
+
+ const TileVariable var = tile.scalar(y_coord, x_coord);
+
+ const std::string actual_var_name = var.str;
+ const std::string expected_var_name = "((half)(" + container[y_coord_clamped][x_coord] + "))";
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLConstantTileAccessScalarVariableBroadcastYTest";
+ }
+
+private:
+ std::vector<int32_t> _height{};
+ std::vector<int32_t> _x_coord{};
+ std::vector<int32_t> _y_coord{};
+};
+
+class CLConstantTileAccessVectorVariablesTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp16;
+
+ CLConstantTileAccessVectorVariablesTest()
+ {
+ _values.push_back({ { "1.2", "3.5" },
+ { "4.2", "1.3" } });
+ _values.push_back({ { "1.2" } });
+ // Mix variable names and values
+ _values.push_back({ { "1.2", "acc", "8.7", "9.3", "ratio", "2.9", "1.7", "0.3" } });
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ int32_t test_idx = 0;
+
+ for(const auto &test : _values)
+ {
+ const CLTile tile(test, dt);
+ const int32_t width = tile.info().width();
+ const int32_t height = tile.info().height();
+
+ for(int32_t row = 0; row < height; ++row)
+ {
+ std::string expected_var_name = "((";
+ expected_var_name += cl_get_variable_datatype_as_string(dt, width);
+ expected_var_name += ")(";
+
+ int32_t col = 0;
+ for(; col < width - 1; ++col)
+ {
+ expected_var_name += test[row][col];
+ expected_var_name += ", ";
+ }
+
+ expected_var_name += test[row][col];
+ expected_var_name += "))";
+
+ const std::string actual_var_name = tile.vector(row).str;
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLConstantTileAccessVectorVariablesTest";
+ }
+
+private:
+ std::vector<TileContainer> _values{};
+};
+
+class CLConstantTileAccessSubVectorVariablesTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp16;
+
+ CLConstantTileAccessSubVectorVariablesTest()
+ {
+ _values.push_back({ { "1.2", "acc", "8.7", "9.3", "ratio", "2.9", "1.7", "0.3" } });
+ _subwidths.push_back(1);
+ _subwidths.push_back(2);
+ _subwidths.push_back(3);
+ _subwidths.push_back(4);
+ _offsets.push_back(1);
+ _offsets.push_back(3);
+ _offsets.push_back(4);
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ size_t test_idx = 0;
+
+ for(auto &test : _values)
+ {
+ for(auto &col_start : _offsets)
+ {
+ for(auto &subwidth : _subwidths)
+ {
+ const CLTile tile(test, dt);
+ const int32_t height = tile.info().height();
+
+ for(int32_t row = 0; row < height; ++row)
+ {
+ std::string expected_var_name = "((";
+ expected_var_name += cl_get_variable_datatype_as_string(dt, subwidth);
+ expected_var_name += ")(";
+
+ int32_t col = col_start;
+ for(; col < subwidth - 1; ++col)
+ {
+ expected_var_name += test[row][col];
+ expected_var_name += ", ";
+ }
+
+ expected_var_name += test[row][col];
+ expected_var_name += "))";
+
+ const std::string actual_var_name = tile.vector(row, col_start, subwidth).str;
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed,
+ test_idx++);
+ }
+ }
+ }
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLConstantTileAccessSubVectorVariablesTest";
+ }
+
+private:
+ std::vector<TileContainer> _values{};
+ std::vector<int32_t> _subwidths{};
+ std::vector<int32_t> _offsets{};
+};
+
+} // namespace ckw
+
+#endif // CKW_TESTS_CLCONSTANTTILETEST_HPP
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterAssignTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterAssignTest.h
new file mode 100644
index 0000000000..f32f797a01
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterAssignTest.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERASSIGNTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERASSIGNTEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterAssignTest : public ITest
+{
+public:
+ CLKernelWriterAssignTest()
+ {
+ _tests.push_back({ 1, 1, 1, 1, DataType::Fp32, "G0__dst = G0__src;\n" }); // Scalar.
+
+ _tests.push_back({ 1, 3, 1, 3, DataType::Fp16, "G0__dst = G0__src;\n" }); // Whole vector.
+
+ _tests.push_back({ 2, 4, 2, 4, DataType::Int8, "G0__dst__0 = G0__src__0;\nG0__dst__1 = G0__src__1;\n" }); // Whole tile.
+
+ _tests.push_back({ 2, 3, 1, 3, DataType::Uint8, "G0__dst__0 = G0__src;\nG0__dst__1 = G0__src;\n" }); // Y-dimension broadcast.
+
+ _tests.push_back({ 2, 4, 2, 1, DataType::Fp32, "G0__dst__0 = (float4)G0__src__0;\nG0__dst__1 = (float4)G0__src__1;\n" }); // X-dimension broadcast.
+
+ _tests.push_back({ 2, 3, 1, 1, DataType::Fp16, "G0__dst__0 = (half3)G0__src;\nG0__dst__1 = (half3)G0__src;\n" }); // X and y dimension broadcast.
+ }
+
+ bool run() override
+ {
+ int32_t test_no = 0;
+ bool all_tests_passed = true;
+
+ for(const auto &test : _tests)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto dst = writer.declare_tile("dst", TileInfo(test.data_type, test.dst_height, test.dst_width));
+ auto src = writer.declare_tile("src", TileInfo(test.data_type, test.src_height, test.src_width));
+
+ writer.start_capture_code();
+
+ writer.op_assign(dst, src);
+
+ VALIDATE_TEST(writer.check_added_code(test.expected_code), all_tests_passed, test_no++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterAssignTest";
+ }
+
+private:
+ struct TestInfo
+ {
+ int32_t dst_height;
+ int32_t dst_width;
+ int32_t src_height;
+ int32_t src_width;
+ DataType data_type;
+ std::string expected_code;
+ };
+
+ std::vector<TestInfo> _tests{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERASSIGNTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterBinaryOpTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterBinaryOpTest.h
new file mode 100644
index 0000000000..44a4df1ce1
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterBinaryOpTest.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERBINARYOPTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERBINARYOPTEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterBinaryOpTest : public ITest
+{
+public:
+ CLKernelWriterBinaryOpTest()
+ {
+ // dst_height, dst_width, dst_data_type, lhs_height, lhs_width, rhs_height, rhs_width, src_data_type, op, expected_code
+ _tests.push_back({ 1, 1, DataType::Fp32, 1, 1, 1, 1, DataType::Fp32, BinaryOp::Add, "G0__dst = G0__lhs + G0__rhs;\n" }); // Scalar.
+
+ _tests.push_back({ 1, 3, DataType::Bool, 1, 3, 1, 3, DataType::Fp16, BinaryOp::Equal, "G0__dst = G0__lhs == G0__rhs;\n" }); // Whole vector.
+
+ _tests.push_back({ 2, 4, DataType::Int8, 2, 4, 2, 4, DataType::Int8, BinaryOp::Min, "G0__dst__0 = min(G0__lhs__0, G0__rhs__0);\nG0__dst__1 = min(G0__lhs__1, G0__rhs__1);\n" }); // Whole tile.
+
+ _tests.push_back({ 2, 3, DataType::Uint8, 1, 3, 2, 3, DataType::Uint8, BinaryOp::BitwiseXOR, "G0__dst__0 = G0__lhs ^ G0__rhs__0;\nG0__dst__1 = G0__lhs ^ G0__rhs__1;\n" }); // LHS y-dimension broadcast.
+
+ _tests.push_back({ 2, 3, DataType::Bool, 2, 3, 1, 3, DataType::Fp32, BinaryOp::Less, "G0__dst__0 = G0__lhs__0 < G0__rhs;\nG0__dst__1 = G0__lhs__1 < G0__rhs;\n" }); // RHS y-dimension broadcast.
+
+ _tests.push_back({ 2, 3, DataType::Fp16, 1, 3, 1, 3, DataType::Fp16, BinaryOp::Max, "G0__dst__0 = fmax(G0__lhs, G0__rhs);\nG0__dst__1 = fmax(G0__lhs, G0__rhs);\n" }); // LHS and RHS y-dimension broadcast.
+
+ _tests.push_back({ 2, 4, DataType::Fp32, 2, 1, 2, 4, DataType::Fp32, BinaryOp::Div, "G0__dst__0 = (float4)G0__lhs__0 / G0__rhs__0;\nG0__dst__1 = (float4)G0__lhs__1 / G0__rhs__1;\n" }); // LHS x-dimension broadcast.
+
+ _tests.push_back({ 2, 4, DataType::Fp16, 2, 4, 2, 1, DataType::Fp16, BinaryOp::Mod, "G0__dst__0 = G0__lhs__0 % (half4)G0__rhs__0;\nG0__dst__1 = G0__lhs__1 % (half4)G0__rhs__1;\n" }); // RHS x-dimension broadcast.
+
+ _tests.push_back({ 2, 4, DataType::Bool, 2, 1, 2, 1, DataType::Fp32, BinaryOp::GreaterEqual, "G0__dst__0 = (float4)G0__lhs__0 >= (float4)G0__rhs__0;\nG0__dst__1 = (float4)G0__lhs__1 >= (float4)G0__rhs__1;\n" }); // LHS and RHS x-dimension broadcast.
+
+ _tests.push_back({ 2, 2, DataType::Fp32, 2, 3, 2, 3, DataType::Fp32, BinaryOp::MatMul_Nt_T,
+ "G0__dst__0.s0 = fma(G0__lhs__0.s0, G0__rhs__0.s0, G0__dst__0.s0);\n"
+ "G0__dst__0.s0 = fma(G0__lhs__0.s1, G0__rhs__0.s1, G0__dst__0.s0);\n"
+ "G0__dst__0.s0 = fma(G0__lhs__0.s2, G0__rhs__0.s2, G0__dst__0.s0);\n"
+ "G0__dst__0.s1 = fma(G0__lhs__0.s0, G0__rhs__1.s0, G0__dst__0.s1);\n"
+ "G0__dst__0.s1 = fma(G0__lhs__0.s1, G0__rhs__1.s1, G0__dst__0.s1);\n"
+ "G0__dst__0.s1 = fma(G0__lhs__0.s2, G0__rhs__1.s2, G0__dst__0.s1);\n"
+ "G0__dst__1.s0 = fma(G0__lhs__1.s0, G0__rhs__0.s0, G0__dst__1.s0);\n"
+ "G0__dst__1.s0 = fma(G0__lhs__1.s1, G0__rhs__0.s1, G0__dst__1.s0);\n"
+ "G0__dst__1.s0 = fma(G0__lhs__1.s2, G0__rhs__0.s2, G0__dst__1.s0);\n"
+ "G0__dst__1.s1 = fma(G0__lhs__1.s0, G0__rhs__1.s0, G0__dst__1.s1);\n"
+ "G0__dst__1.s1 = fma(G0__lhs__1.s1, G0__rhs__1.s1, G0__dst__1.s1);\n"
+ "G0__dst__1.s1 = fma(G0__lhs__1.s2, G0__rhs__1.s2, G0__dst__1.s1);\n" });
+ }
+
+ bool run() override
+ {
+ int32_t test_no = 0;
+ bool all_tests_passed = true;
+
+ for(const auto &test : _tests)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto dst = writer.declare_tile("dst", TileInfo(test.dst_data_type, test.dst_height, test.dst_width));
+ auto lhs = writer.declare_tile("lhs", TileInfo(test.src_data_type, test.lhs_height, test.lhs_width));
+ auto rhs = writer.declare_tile("rhs", TileInfo(test.src_data_type, test.rhs_height, test.rhs_width));
+
+ writer.start_capture_code();
+
+ writer.op_binary(dst, test.op, lhs, rhs);
+
+ VALIDATE_TEST(writer.check_added_code(test.expected_code), all_tests_passed, test_no++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterBinaryOpTest";
+ }
+
+private:
+ struct TestInfo
+ {
+ int32_t dst_height;
+ int32_t dst_width;
+ DataType dst_data_type;
+ int32_t lhs_height;
+ int32_t lhs_width;
+ int32_t rhs_height;
+ int32_t rhs_width;
+ DataType src_data_type;
+ BinaryOp op;
+ std::string expected_code;
+ };
+
+ std::vector<TestInfo> _tests{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERBINARYOPTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterCastTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterCastTest.h
new file mode 100644
index 0000000000..a185cce545
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterCastTest.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERCASTTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERCASTTEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/ConvertPolicy.h"
+#include "ckw/types/DataType.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterCastTest : public ITest
+{
+public:
+ CLKernelWriterCastTest()
+ {
+ _tests.push_back({ 1, 1, DataType::Fp16, 1, 1, DataType::Fp32, ConvertPolicy::None, "G0__dst = convert_half(G0__src);\n" }); // Scalar.
+
+ _tests.push_back({ 1, 3, DataType::Int32, 1, 3, DataType::Fp16, ConvertPolicy::Saturate, "G0__dst = convert_int3_sat(G0__src);\n" }); // Whole vector.
+
+ _tests.push_back({ 2, 4, DataType::Uint16, 2, 4, DataType::Int8, ConvertPolicy::Saturate, "G0__dst__0 = convert_ushort4_sat(G0__src__0);\nG0__dst__1 = convert_ushort4_sat(G0__src__1);\n" }); // Whole tile.
+
+ _tests.push_back({ 2, 3, DataType::Int8, 1, 3, DataType::Uint8, ConvertPolicy::None, "G0__dst__0 = convert_char3(G0__src);\nG0__dst__1 = convert_char3(G0__src);\n" }); // Y-dimension broadcast.
+
+ _tests.push_back({ 2, 4, DataType::Fp16, 2, 1, DataType::Fp32, ConvertPolicy::None, "G0__dst__0 = (half4)convert_half(G0__src__0);\nG0__dst__1 = (half4)convert_half(G0__src__1);\n" }); // X-dimension broadcast.
+
+ _tests.push_back({ 2, 3, DataType::Fp32, 1, 1, DataType::Fp16, ConvertPolicy::None, "G0__dst__0 = (float3)convert_float(G0__src);\nG0__dst__1 = (float3)convert_float(G0__src);\n" }); // X and y dimension broadcast.
+ }
+
+ bool run() override
+ {
+ int32_t test_no = 0;
+ bool all_tests_passed = true;
+
+ for(const auto &test : _tests)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto dst = writer.declare_tile("dst", TileInfo(test.dst_data_type, test.dst_height, test.dst_width));
+ auto src = writer.declare_tile("src", TileInfo(test.src_data_type, test.src_height, test.src_width));
+
+ writer.start_capture_code();
+
+ writer.op_cast(dst, src, test.policy);
+
+ VALIDATE_TEST(writer.check_added_code(test.expected_code), all_tests_passed, test_no++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterCastTest";
+ }
+
+private:
+ struct TestInfo
+ {
+ int32_t dst_height;
+ int32_t dst_width;
+ DataType dst_data_type;
+ int32_t src_height;
+ int32_t src_width;
+ DataType src_data_type;
+ ConvertPolicy policy;
+ std::string expected_code;
+ };
+
+ std::vector<TestInfo> _tests{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERCASTTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterCommentTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterCommentTest.h
new file mode 100644
index 0000000000..b36c3905ec
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterCommentTest.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERCOMMENTTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERCOMMENTTEST_H
+
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+namespace ckw
+{
+
+class CLKernelWriterCommentTest : public ITest
+{
+public:
+ CLKernelWriterCommentTest()
+ {
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ writer.op_comment("previous code");
+
+ writer.start_capture_code();
+
+ writer.op_comment("code under test 0");
+ writer.op_comment("code under test 1");
+
+#ifdef COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+ constexpr auto expected_code = "// code under test 0\n// code under test 1\n";
+#else // COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+ constexpr auto expected_code = "";
+#endif // COMPUTE_KERNEL_WRITER_DEBUG_ENABLED
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, 0);
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterCommentTest";
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERCOMMENTTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterDeclareConstantTileTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterDeclareConstantTileTest.h
new file mode 100644
index 0000000000..661a8328e8
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterDeclareConstantTileTest.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERDECLARECONSTANTTILETEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERDECLARECONSTANTTILETEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/ConstantData.h"
+#include "ckw/types/DataType.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+#include "validation/tests/common/Common.h"
+
+#include <string>
+#include <tuple>
+#include <vector>
+
+namespace ckw
+{
+class CLKernelWriterDeclareConstantTileTest : public ITest
+{
+ using TestConfig = std::tuple<ConstantData, DataType, int32_t, int32_t, std::string>;
+public:
+ CLKernelWriterDeclareConstantTileTest()
+ {
+ _configs = {
+ // ConstantData, DataType, Height, Width
+ {ConstantData({{1}}, DataType::Int32), DataType::Int32, 1, 1,
+ "G0__tile = ((int)(1));\n"},
+ {ConstantData({{1U}}, DataType::Uint32), DataType::Uint32, 1, 1,
+ "G0__tile = ((uint)(1));\n"},
+ {ConstantData({{1, 2}}, DataType::Int8), DataType::Int8, 1, 2,
+ "G0__tile = ((char2)(1, 2));\n"},
+ {ConstantData({{1, -2}, {-3, 4}}, DataType::Int32), DataType::Int32, 2, 2,
+ "G0__tile__0 = ((int2)(1, -2));\nG0__tile__1 = ((int2)(-3, 4));\n"},
+ {ConstantData({{1.0f, -2.0f}}, DataType::Fp16), DataType::Fp16, 1, 2,
+ "G0__tile = ((half2)(1.000000000e+00, -2.000000000e+00));\n"},
+ {ConstantData({{/* FLT_MAX */ 340282346638528859811704183484516925440.0f, -2.0f, 3.0f}}, DataType::Fp32), DataType::Fp32, 1, 3,
+ "G0__tile = ((float3)(3.402823466e+38, -2.000000000e+00, 3.000000000e+00));\n"},
+ {ConstantData({{1.0f, -1e-20f, 2e-20f, /* FLT_EPS */ 1.1920928955078125e-7f}}, DataType::Fp32), DataType::Fp32, 1, 4,
+ "G0__tile = ((float4)(1.000000000e+00, -9.999999683e-21, 1.999999937e-20, 1.192092896e-07));\n"},
+ {ConstantData({{0.5f, 2.1e-30f, /* FLT_MIN */ 1.175494350822287507969e-38f}}, DataType::Fp32), DataType::Fp32, 1, 3,
+ "G0__tile = ((float3)(5.000000000e-01, 2.099999969e-30, 1.175494351e-38));\n"},
+ {ConstantData({{true}, {false}, {false}}, DataType::Bool), DataType::Bool, 3, 1,
+ "G0__tile__0 = ((bool)(1));\nG0__tile__1 = ((bool)(0));\nG0__tile__2 = ((bool)(0));\n"}
+ };
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+ int test_idx = 0;
+
+ for(TestConfig _config: _configs)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+ const ConstantData const_data = std::get<0>(_config);
+ const DataType data_type = std::get<1>(_config);
+ const size_t height = std::get<2>(_config);
+ const size_t width = std::get<3>(_config);
+ const std::string expected_code = std::get<4>(_config);
+
+ TileOperand tile = writer.declare_tile("tile", TileInfo(data_type, height, width));
+ writer.start_capture_code();
+ TileOperand const_tile = writer.declare_constant_tile(const_data);
+ writer.op_assign(tile, const_tile);
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_idx++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterDeclareConstantTileTest";
+ }
+
+private:
+ std::vector<TestConfig> _configs {};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERDECLARECONSTANTTILETEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterDeclareTensorTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterDeclareTensorTest.h
new file mode 100644
index 0000000000..855c747f13
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterDeclareTensorTest.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERDECLARETENSORTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERDECLARETENSORTEST_H
+
+#include "ckw/Error.h"
+#include "ckw/Kernel.h"
+#include "ckw/KernelArgument.h"
+#include "ckw/TensorInfo.h"
+#include "ckw/types/TensorComponentType.h"
+#include "ckw/types/TensorDataLayout.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+
+namespace ckw
+{
+
+class CLKernelWriterDeclareTensorTest : public ITest
+{
+public:
+ CLKernelWriterDeclareTensorTest()
+ {
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterDeclareTensorTest";
+ }
+
+ bool run() override
+ {
+ auto all_tests_passed = true;
+
+ CLKernelWriter writer;
+
+ auto src = writer.declare_tensor_argument("src", TensorInfo(DataType::Fp32, TensorShape{ 2, 3, 4, 5 }, TensorDataLayout::Nhwc, 0));
+ auto dst = writer.declare_tensor_argument("dst", TensorInfo(DataType::Fp32, TensorShape{ 6, 7, 8, 9 }, TensorDataLayout::Nhwc, 1));
+
+ auto src_dim0 = src.dim0();
+ auto src_stride2 = src.stride2();
+ auto src_offset_element = src.offset_first_element_in_bytes();
+
+ auto dst_dim1 = dst.dim0();
+
+ auto src_dim0_again = src.dim0();
+
+ CKW_UNUSED(src_dim0, src_stride2, src_offset_element, dst_dim1, src_dim0_again);
+
+ const auto kernel = writer.emit_kernel("test_kernel");
+
+ const std::string expected_code =
+ "__kernel void test_kernel\n"
+ "(\n"
+ "int G0__src_dim0,\n"
+ "int G0__src_stride2,\n"
+ "int G0__src_offset_first_element,\n"
+ "int G0__dst_dim0\n"
+ ")\n"
+ "{\n"
+ "}\n";
+
+ std::string actual_code = kernel->source_code();
+
+ std::size_t pos = actual_code.find("__kernel");
+
+ if (pos != std::string::npos)
+ {
+ // Remove text before "__kernel"
+ actual_code = actual_code.substr(pos);
+ }
+
+ int test_id = 0;
+ VALIDATE_TEST(kernel->arguments().size() == 4, all_tests_passed, test_id++);
+ test_tensor_component_argument(kernel->arguments()[0], 0, TensorComponentType::Dim0, all_tests_passed, test_id);
+ test_tensor_component_argument(kernel->arguments()[1], 0, TensorComponentType::Stride2, all_tests_passed, test_id);
+ test_tensor_component_argument(kernel->arguments()[2], 0, TensorComponentType::OffsetFirstElement, all_tests_passed, test_id);
+ test_tensor_component_argument(kernel->arguments()[3], 1, TensorComponentType::Dim0, all_tests_passed, test_id);
+ VALIDATE_TEST(actual_code == expected_code, all_tests_passed, test_id++);
+
+ return all_tests_passed;
+ }
+
+ void test_tensor_component_argument(const KernelArgument &arg, int32_t tensor_id, TensorComponentType component_type, bool &all_tests_passed, int &test_id)
+ {
+ VALIDATE_TEST(arg.type() == KernelArgument::Type::TensorComponent, all_tests_passed, test_id++);
+ VALIDATE_TEST(arg.id() == tensor_id, all_tests_passed, test_id++);
+ VALIDATE_TEST(arg.tensor_component_type() == component_type, all_tests_passed, test_id++);
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERDECLARETENSORTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterDeclareTileTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterDeclareTileTest.h
new file mode 100644
index 0000000000..4f728bc1bf
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterDeclareTileTest.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITER_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITER_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+#include "validation/tests/common/Common.h"
+
+#include <vector>
+
+namespace ckw
+{
+
+using CLKernelWriterDeclareTileConfig = std::tuple<DataType, int32_t, int32_t, std::string>;
+
+class CLKernelWriterDeclareTileTest : public ITest
+{
+public:
+ CLKernelWriterDeclareTileTest()
+ {
+ _configs = {
+ {DataType::Fp32, 4, 4, "float4 G0__a_tile"},
+ {DataType::Uint8, 4, 1, "uchar G0__a_tile"},
+ {DataType::Int8, 4, 2, "char2 G0__a_tile"},
+ {DataType::Bool, 9, 3, "bool3 G0__a_tile"},
+ {DataType::Fp16, 4, 16, "half16 G0__a_tile"},
+ {DataType::Uint32, 1, 8, "uint8 G0__a_tile"},
+ {DataType::Uint16, 2, 3, "ushort3 G0__a_tile"},
+ };
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+ int32_t test_idx = 0;
+
+ for(auto _config: _configs)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+ writer.start_capture_code();
+
+ const DataType data_type = std::get<0>(_config);
+ const int32_t height = std::get<1>(_config);
+ const int32_t width = std::get<2>(_config);
+ const std::string prefix = std::get<3>(_config);
+
+ // expected output
+ std::string expected_code = "";
+ for(int32_t row = 0; row < height; ++row)
+ {
+ expected_code += prefix + ((height > 1) ? std::string("__") + std::to_string(row) : "") + ";\n";
+ }
+
+ TileInfo tile_info(data_type, height, width);
+ writer.declare_tile("a_tile", tile_info);
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_idx++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterDeclareTileTest";
+ }
+
+private:
+ std::vector<CLKernelWriterDeclareTileConfig> _configs {};
+};
+
+} // namespace ckw
+
+#endif /* CKW_VALIDATION_TESTS_CLKERNELWRITER_H */
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterForTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterForTest.h
new file mode 100644
index 0000000000..beb39966b2
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterForTest.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERFORTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERFORTEST_H
+
+#include "ckw/Error.h"
+#include "ckw/TileInfo.h"
+#include "ckw/types/Operators.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+namespace ckw
+{
+
+class CLKernelWriterForTest : public ITest
+{
+public:
+ CLKernelWriterForTest()
+ {
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto idx = writer.declare_tile("idx", TileInfo(DataType::Int32, 1, 1));
+ auto len = writer.declare_tile("len", TileInfo(DataType::Int32, 1, 1));
+ auto addr = writer.declare_tile("addr", TileInfo(DataType::Int32, 1, 1));
+ auto esize = writer.declare_tile("esize", TileInfo(DataType::Int32, 1, 1));
+
+ writer.start_capture_code();
+
+ writer.op_for_loop(
+ idx, BinaryOp::Less, len, addr, AssignmentOp::Increment, esize,
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Fp32, 1, 3));
+ CKW_UNUSED(tile);
+ });
+
+ constexpr auto expected_code =
+ "for (; G0__idx < G0__len; G0__addr += G0__esize)\n"
+ "{\n"
+ "float3 G1__tile;\n"
+ "}\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, 0);
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterForTest";
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERFORTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterGetGlobalIdTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterGetGlobalIdTest.h
new file mode 100644
index 0000000000..fa34b3f5df
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterGetGlobalIdTest.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERGETGLOBALIDTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERGETGLOBALIDTEST_H
+
+#include "ckw/TileInfo.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+namespace ckw
+{
+
+class CLKernelWriterGetGlobalIdTest : public ITest
+{
+public:
+ CLKernelWriterGetGlobalIdTest()
+ {
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto gid = writer.declare_tile("gid", TileInfo(DataType::Int32));
+
+ writer.start_capture_code();
+
+ writer.op_get_global_id(gid, 0);
+ writer.op_get_global_id(gid, 1);
+ writer.op_get_global_id(gid, 2);
+
+ constexpr auto expected_code = "G0__gid = get_global_id(0);\nG0__gid = get_global_id(1);\nG0__gid = get_global_id(2);\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, 0);
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterGetGlobalIdTest";
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERGETGLOBALIDTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterIfTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterIfTest.h
new file mode 100644
index 0000000000..3964bd76d4
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterIfTest.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERIFTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERIFTEST_H
+
+#include "ckw/Error.h"
+#include "ckw/TileInfo.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+
+namespace ckw
+{
+
+class CLKernelWriterIfTest : public ITest
+{
+public:
+ CLKernelWriterIfTest()
+ {
+ }
+
+ bool run() override
+ {
+ int32_t test_no = 0;
+ bool all_tests_passed = true;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto lhs = writer.declare_tile("lhs", TileInfo(DataType::Fp32, 1, 1));
+ auto rhs = writer.declare_tile("rhs", TileInfo(DataType::Fp32, 1, 1));
+
+ // The first if block.
+ {
+ writer.start_capture_code();
+
+ writer.op_if(
+ lhs, BinaryOp::Equal, rhs,
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Fp16, 2, 3));
+ CKW_UNUSED(tile);
+ });
+
+ constexpr auto expected_code =
+ "if (G0__lhs == G0__rhs)\n"
+ "{\n"
+ "half3 G1__tile__0;\n"
+ "half3 G1__tile__1;\n"
+ "}\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_no++);
+ }
+
+ // The second if block - The ID space inside the if block should change.
+ {
+ writer.start_capture_code();
+
+ writer.op_if(
+ lhs, BinaryOp::Equal, rhs,
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Fp16, 2, 3));
+ CKW_UNUSED(tile);
+ });
+
+ constexpr auto expected_code =
+ "if (G0__lhs == G0__rhs)\n"
+ "{\n"
+ "half3 G2__tile__0;\n"
+ "half3 G2__tile__1;\n"
+ "}\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_no++);
+ }
+
+ // The if-else block - The ID space in each block should change.
+ {
+ writer.start_capture_code();
+
+ writer.op_if(
+ lhs, BinaryOp::Equal, rhs,
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Fp16, 2, 3));
+ CKW_UNUSED(tile);
+ });
+ writer.op_else(
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Uint8, 1, 4));
+ CKW_UNUSED(tile);
+ });
+
+ constexpr auto expected_code =
+ "if (G0__lhs == G0__rhs)\n"
+ "{\n"
+ "half3 G3__tile__0;\n"
+ "half3 G3__tile__1;\n"
+ "}\n"
+ "else\n"
+ "{\n"
+ "uchar4 G4__tile;\n"
+ "}\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_no++);
+ }
+
+ // If-else if block.
+ {
+ writer.start_capture_code();
+
+ writer.op_if(
+ lhs, BinaryOp::Equal, rhs,
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Fp32, 1, 3));
+ CKW_UNUSED(tile);
+ });
+ writer.op_else_if(
+ lhs, BinaryOp::Less, rhs,
+ [&]()
+ {
+ auto tile = writer.declare_tile("tile", TileInfo(DataType::Int8, 1, 4));
+ CKW_UNUSED(tile);
+ });
+
+ constexpr auto expected_code =
+ "if (G0__lhs == G0__rhs)\n"
+ "{\n"
+ "float3 G5__tile;\n"
+ "}\n"
+ "else if (G0__lhs < G0__rhs)\n"
+ "{\n"
+ "char4 G6__tile;\n"
+ "}\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_no++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterIfTest";
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERIFTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterOpLoadIndirectTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterOpLoadIndirectTest.h
new file mode 100644
index 0000000000..dacf3cd435
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterOpLoadIndirectTest.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITEROPLOADINDIRECTTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITEROPLOADINDIRECTTEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "ckw/TensorSampler.h"
+#include "ckw/types/MemoryOperation.h"
+#include "ckw/types/TensorSamplerTypes.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+#include "validation/tests/common/Common.h"
+
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterOpLoadIndirectTest : public ITest
+{
+private:
+ using AddressModeX = TensorSamplerAddressModeX;
+ using AddressModeY = TensorSamplerAddressModeY;
+ using AddressModeZ = TensorSamplerAddressModeZ;
+ using Format = TensorSamplerFormat;
+ using Storage = TensorStorageType;
+
+ struct Coordinates
+ {
+ Coordinates(std::string x, std::string y, std::string z, std::string batch)
+ : x(x), y(y), z(z), batch(batch)
+ {
+ }
+
+ std::string x;
+ std::string y;
+ std::string z;
+ std::string batch;
+ };
+
+ struct SamplerData
+ {
+ SamplerData(Format format, AddressModeX mode_x, AddressModeY mode_y, AddressModeZ mode_z)
+ : format(format), mode_x(mode_x), mode_y(mode_y), mode_z(mode_z)
+ {
+ }
+
+ Format format;
+ AddressModeX mode_x;
+ AddressModeY mode_y;
+ AddressModeZ mode_z;
+ };
+
+ using CLKernelWriterOpLoadIndirectConfig = std::tuple<TileInfo, TensorStorageType, SamplerData, Coordinates, std::string>;
+
+public:
+ CLKernelWriterOpLoadIndirectTest()
+ {
+ const std::string fp_2x3_tile = R"_(
+G0__tile__0 = vload3(0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__indirect_addr__0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+G0__tile__1 = vload3(0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__indirect_addr__1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+)_";
+
+ const std::string half_2x4_yz_collapsed_y_clamped_to_border_max_only_image = R"_(
+G0__tile__0 = read_imageh(G0__tensor_img2d, CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST, (int2)((G0__x) >> 2, (G0__indirect_addr__0 + (G0__b) * G0__tensor_dim1xdim2 * 1)));
+G0__tile__1 = read_imageh(G0__tensor_img2d, CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST, (int2)((G0__x) >> 2, (G0__indirect_addr__1 + (G0__b) * G0__tensor_dim1xdim2 * 1)));
+)_";
+
+ const std::string int_2x4_y_skip_less_than_zero = R"_(
+if(G0__indirect_addr__0 >= 0)
+{
+G0__tile__0 = vload4(0, (__global int*)(G0__tensor_ptr + (G0__x) * sizeof(int) + (G0__indirect_addr__0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+}
+if(G0__indirect_addr__1 >= 0)
+{
+G0__tile__1 = vload4(0, (__global int*)(G0__tensor_ptr + (G0__x) * sizeof(int) + (G0__indirect_addr__1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+}
+)_";
+
+ // tensor shape in x-dim is 10 (thus the 8, 2 vloads in if, else blocks respectively)
+ const std::string uint16_3x8_yz_collapsed_b_eq_0_x_overlapping_min_y_skip_less_than_zero = R"_(
+if(G0__x > 0)
+{
+if(G0__indirect_addr__0 >= 0)
+{
+G0__tile__0 = vload8(0, (__global ushort*)(G0__tensor_ptr + (G0__x) * sizeof(ushort) + (G0__indirect_addr__0) * G0__tensor_stride1 + (G0__0) * G0__tensor_stride3));
+}
+if(G0__indirect_addr__1 >= 0)
+{
+G0__tile__1 = vload8(0, (__global ushort*)(G0__tensor_ptr + (G0__x) * sizeof(ushort) + (G0__indirect_addr__1) * G0__tensor_stride1 + (G0__0) * G0__tensor_stride3));
+}
+if(G0__indirect_addr__2 >= 0)
+{
+G0__tile__2 = vload8(0, (__global ushort*)(G0__tensor_ptr + (G0__x) * sizeof(ushort) + (G0__indirect_addr__2) * G0__tensor_stride1 + (G0__0) * G0__tensor_stride3));
+}
+}
+else
+{
+if(G0__indirect_addr__0 >= 0)
+{
+G0__tile__0.s01 = vload2(0, (__global ushort*)(G0__tensor_ptr + (G0__x + 0) * sizeof(ushort) + (G0__indirect_addr__0) * G0__tensor_stride1 + (G0__0) * G0__tensor_stride3));
+}
+if(G0__indirect_addr__1 >= 0)
+{
+G0__tile__1.s01 = vload2(0, (__global ushort*)(G0__tensor_ptr + (G0__x + 0) * sizeof(ushort) + (G0__indirect_addr__1) * G0__tensor_stride1 + (G0__0) * G0__tensor_stride3));
+}
+if(G0__indirect_addr__2 >= 0)
+{
+G0__tile__2.s01 = vload2(0, (__global ushort*)(G0__tensor_ptr + (G0__x + 0) * sizeof(ushort) + (G0__indirect_addr__2) * G0__tensor_stride1 + (G0__0) * G0__tensor_stride3));
+}
+}
+)_";
+
+ // Configs Bundled
+ _configs = {
+ {
+ TileInfo(DataType::Fp32, 2, 3),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::None, AddressModeY::None, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ fp_2x3_tile
+ },
+ {
+ TileInfo(DataType::Fp16, 2, 4),
+ TensorStorageType::Texture2dReadOnly,
+ SamplerData(Format::Dim0_Dim1xDim2_1, AddressModeX::None, AddressModeY::ClampToBorderMaxOnly, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ half_2x4_yz_collapsed_y_clamped_to_border_max_only_image
+ },
+ {
+ TileInfo(DataType::Int32, 2, 4),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::None, AddressModeY::SkipLessThanZero, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ int_2x4_y_skip_less_than_zero
+ },
+ {
+ TileInfo(DataType::Uint16, 3, 8),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1xDim2_1, AddressModeX::OverlappingMin, AddressModeY::SkipLessThanZero, AddressModeZ::None),
+ Coordinates("x", "y", "z", "0"),
+ uint16_3x8_yz_collapsed_b_eq_0_x_overlapping_min_y_skip_less_than_zero
+ }
+ };
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+ int32_t test_idx = 0;
+
+ for(auto _config: _configs)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ const TileInfo tile_info = std::get<0>(_config);
+ const Storage storage = std::get<1>(_config);
+ const SamplerData sampler_data = std::get<2>(_config);
+ const Coordinates coord = std::get<3>(_config);
+ const std::string expected_code = std::get<4>(_config).substr(1); // ignore initial newline, which was added for convenience
+
+ TileOperand tile_op = writer.declare_tile("tile", TileInfo(tile_info.data_type(), tile_info.height(), tile_info.width()));
+ TileOperand indirect_addr_op = writer.declare_tile("indirect_addr", TileInfo(DataType::Int32, tile_info.height(), 1)); // (M0, 1)
+ TileOperand x_op = writer.declare_tile(coord.x, TileInfo(DataType::Int32));
+ TileOperand z_op = writer.declare_tile(coord.z, TileInfo(DataType::Int32));
+ TileOperand batch_op = writer.declare_tile(coord.batch, TileInfo(DataType::Int32));
+
+ TensorShape tensor_shape {10, 10, 10, 10};
+ TensorInfo tensor_info(tile_info.data_type(), tensor_shape, TensorDataLayout::Nhwc, 0 /* id */);
+ TensorOperand tensor_op = writer.declare_tensor_argument("tensor", tensor_info);
+ TensorSampler sampler(storage, sampler_data.format, sampler_data.mode_x, sampler_data.mode_y, sampler_data.mode_z);
+
+ writer.start_capture_code();
+ writer.op_load_indirect(tile_op, tensor_op, sampler, x_op, indirect_addr_op, z_op, batch_op);
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_idx++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterOpLoadIndirectTest";
+ }
+
+private:
+ std::vector<CLKernelWriterOpLoadIndirectConfig> _configs {};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITEROPLOADINDIRECTTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterOpLoadStoreTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterOpLoadStoreTest.h
new file mode 100644
index 0000000000..870e80ee9a
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterOpLoadStoreTest.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITEROPLOADSTORETEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITEROPLOADSTORETEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+#include "validation/tests/common/Common.h"
+
+#include "ckw/TensorSampler.h"
+#include "ckw/types/MemoryOperation.h"
+#include "ckw/types/TensorSamplerTypes.h"
+
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterOpLoadStoreTest : public ITest
+{
+private:
+ using AddressModeX = TensorSamplerAddressModeX;
+ using AddressModeY = TensorSamplerAddressModeY;
+ using AddressModeZ = TensorSamplerAddressModeZ;
+ using Format = TensorSamplerFormat;
+ using Storage = TensorStorageType;
+
+ struct Coordinates
+ {
+ Coordinates(std::string x, std::string y, std::string z, std::string batch)
+ : x(x), y(y), z(z), batch(batch)
+ {
+ }
+
+ std::string x;
+ std::string y;
+ std::string z;
+ std::string batch;
+ };
+
+ struct SamplerData
+ {
+ SamplerData(Format format, AddressModeX mode_x, AddressModeY mode_y, AddressModeZ mode_z)
+ : format(format), mode_x(mode_x), mode_y(mode_y), mode_z(mode_z)
+ {
+ }
+
+ Format format;
+ AddressModeX mode_x;
+ AddressModeY mode_y;
+ AddressModeZ mode_z;
+ };
+
+ struct Dilations
+ {
+ Dilations(std::string dilation_x, std::string dilation_y)
+ : dilation_x(dilation_x), dilation_y(dilation_y)
+ {
+ }
+
+ std::string dilation_x;
+ std::string dilation_y;
+ };
+
+ using CLKernelWriterOpLoadStoreConfig = std::tuple<MemoryOperation, TileInfo, TensorStorageType, SamplerData, Coordinates, Dilations, std::string>;
+
+public:
+ CLKernelWriterOpLoadStoreTest()
+ {
+ // Cases
+ const std::string load_fp_2x3_tile = R"_(
+G0__tile__0 = vload3(0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__y + 0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+G0__tile__1 = vload3(0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__y + 1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+)_";
+ const std::string load_half_2x4_tile_image_clamp_y = R"_(
+G0__tile__0 = read_imageh(G0__tensor_img2d, CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST, (int2)((G0__x) >> 2, (G0__y + 0 + (G0__z) * G0__tensor_dim1 + (G0__b) * G0__tensor_dim1 * G0__tensor_dim2)));
+G0__tile__1 = read_imageh(G0__tensor_img2d, CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST, (int2)((G0__x) >> 2, (G0__y + 1 + (G0__z) * G0__tensor_dim1 + (G0__b) * G0__tensor_dim1 * G0__tensor_dim2)));
+)_";
+ const std::string store_fp_2x3_tile = R"_(
+vstore3(G0__tile__0, 0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__y + 0) * G0__tensor_stride1 + (G0__b) * G0__tensor_stride3));
+vstore3(G0__tile__1, 0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__y + 1) * G0__tensor_stride1 + (G0__b) * G0__tensor_stride3));
+)_";
+ const std::string store_int8_4x4_y_dilation_batch_eq_0 = R"_(
+vstore4(G0__tile__0, 0, (__global char*)(G0__tensor_ptr + (((int)(1))) * sizeof(char) + (G0__y + 0 * G0__y_dilation) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(0))) * G0__tensor_stride3));
+vstore4(G0__tile__1, 0, (__global char*)(G0__tensor_ptr + (((int)(1))) * sizeof(char) + (G0__y + 1 * G0__y_dilation) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(0))) * G0__tensor_stride3));
+vstore4(G0__tile__2, 0, (__global char*)(G0__tensor_ptr + (((int)(1))) * sizeof(char) + (G0__y + 2 * G0__y_dilation) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(0))) * G0__tensor_stride3));
+vstore4(G0__tile__3, 0, (__global char*)(G0__tensor_ptr + (((int)(1))) * sizeof(char) + (G0__y + 3 * G0__y_dilation) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(0))) * G0__tensor_stride3));
+)_";
+ // tensor dimension is 10
+ const std::string load_fp_2x3_tile_x_overlapping_min_y_eq_0_batch_eq_1 = R"_(
+if(G0__x > 0)
+{
+G0__tile__0 = vload3(0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (((int)(0)) + 0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(1))) * G0__tensor_stride3));
+G0__tile__1 = vload3(0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (((int)(0)) + 1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(1))) * G0__tensor_stride3));
+}
+else
+{
+G0__tile__0.s0 = *((__global float*)(G0__tensor_ptr + (G0__x + 0) * sizeof(float) + (((int)(0)) + 0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(1))) * G0__tensor_stride3));
+G0__tile__1.s0 = *((__global float*)(G0__tensor_ptr + (G0__x + 0) * sizeof(float) + (((int)(0)) + 1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (((int)(1))) * G0__tensor_stride3));
+}
+)_";
+ const std::string store_fp_2x3_tile_x_overlapping_min_y_clamp_to_border_max_only = R"_(
+if(G0__x > 0)
+{
+if(G0__y + 0 < G0__tensor_dim1)
+{
+vstore3(G0__tile__0, 0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__y + 0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+}
+else
+{
+G0__tile__0 = 0.0f;
+}
+if(G0__y + 1 < G0__tensor_dim1)
+{
+vstore3(G0__tile__1, 0, (__global float*)(G0__tensor_ptr + (G0__x) * sizeof(float) + (G0__y + 1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3));
+}
+else
+{
+G0__tile__1 = 0.0f;
+}
+}
+else
+{
+if(G0__y + 0 < G0__tensor_dim1)
+{
+*((__global float*)(G0__tensor_ptr + (G0__x + 0) * sizeof(float) + (G0__y + 0) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3)) = G0__tile__0.s0;
+}
+else
+{
+G0__tile__0.s0 = 0.0f;
+}
+if(G0__y + 1 < G0__tensor_dim1)
+{
+*((__global float*)(G0__tensor_ptr + (G0__x + 0) * sizeof(float) + (G0__y + 1) * G0__tensor_stride1 + (G0__z) * G0__tensor_stride2 + (G0__b) * G0__tensor_stride3)) = G0__tile__1.s0;
+}
+else
+{
+G0__tile__1.s0 = 0.0f;
+}
+}
+)_";
+ const std::string store_half_2x4_tile_x_image_y_dilation = R"_(
+write_imageh(G0__tensor_img2d, (int2)((G0__x) >> 2, (((int)(0)) + 0 * G0__y_dilation + (G0__z) * G0__tensor_dim1 + (((int)(1))) * G0__tensor_dim1 * G0__tensor_dim2)), G0__tile__0);
+write_imageh(G0__tensor_img2d, (int2)((G0__x) >> 2, (((int)(0)) + 1 * G0__y_dilation + (G0__z) * G0__tensor_dim1 + (((int)(1))) * G0__tensor_dim1 * G0__tensor_dim2)), G0__tile__1);
+)_";
+
+ // Configs Bundled
+ _configs = {
+ // op, tile, storage, sampler, coordinates, dilation, expected
+ {
+ MemoryOperation::Load,
+ TileInfo(DataType::Fp32, 2, 3),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::None, AddressModeY::None, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ Dilations("1", "1"),
+ load_fp_2x3_tile
+ },
+ {
+ MemoryOperation::Load,
+ TileInfo(DataType::Fp16, 2, 4),
+ TensorStorageType::Texture2dReadOnly,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::None, AddressModeY::ClampToBorderMaxOnly, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ Dilations("1", "1"),
+ load_half_2x4_tile_image_clamp_y
+ },
+ {
+ MemoryOperation::Store,
+ TileInfo(DataType::Fp32, 2, 3),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1xDim2_1,AddressModeX::None, AddressModeY::None, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ Dilations("1", "1"),
+ store_fp_2x3_tile
+ },
+ {
+ MemoryOperation::Store,
+ TileInfo(DataType::Int8, 4, 4),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::None, AddressModeY::None, AddressModeZ::None),
+ Coordinates("1", "y", "z", "0"),
+ Dilations("1", "y_dilation"),
+ store_int8_4x4_y_dilation_batch_eq_0
+ },
+ {
+ MemoryOperation::Load,
+ TileInfo(DataType::Fp32, 2, 3),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::OverlappingMin, AddressModeY::None, AddressModeZ::None),
+ Coordinates("x", "0", "z", "1"),
+ Dilations("1", "1"),
+ load_fp_2x3_tile_x_overlapping_min_y_eq_0_batch_eq_1
+ },
+ {
+ MemoryOperation::Store,
+ TileInfo(DataType::Fp32, 2, 3),
+ TensorStorageType::BufferUint8Ptr,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::OverlappingMin, AddressModeY::ClampToBorderMaxOnly, AddressModeZ::None),
+ Coordinates("x", "y", "z", "b"),
+ Dilations("1", "1"),
+ store_fp_2x3_tile_x_overlapping_min_y_clamp_to_border_max_only
+ },
+ {
+ MemoryOperation::Store,
+ TileInfo(DataType::Fp16, 2, 4),
+ TensorStorageType::Texture2dWriteOnly,
+ SamplerData(Format::Dim0_Dim1_Dim2, AddressModeX::None, AddressModeY::None, AddressModeZ::None),
+ Coordinates("x", "0", "z", "1"),
+ Dilations("1", "y_dilation"),
+ store_half_2x4_tile_x_image_y_dilation
+ }
+ };
+ }
+
+ TileOperand declare_tile_helper(KernelWriter &writer, std::string tile)
+ {
+ if(tile == "0" || tile == "1")
+ {
+ return writer.declare_constant_tile(ConstantData({{std::stoi(tile)}}, DataType::Int32));
+ }
+ else
+ {
+ return writer.declare_tile(tile, TileInfo(DataType::Int32));
+ }
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+ int32_t test_idx = 0;
+
+ for(auto _config: _configs)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ const MemoryOperation op = std::get<0>(_config);
+ const TileInfo tile_info = std::get<1>(_config);
+ const Storage storage = std::get<2>(_config);
+ const SamplerData sampler_data = std::get<3>(_config);
+ const Coordinates coord = std::get<4>(_config);
+ const Dilations dilations = std::get<5>(_config);
+ const std::string expected_code = std::get<6>(_config).substr(1); // ignore initial newline, which was added for convenience
+
+ TileOperand tile_op = writer.declare_tile("tile", tile_info);
+ TileOperand x_op = declare_tile_helper(writer, coord.x);
+ TileOperand y_op = declare_tile_helper(writer, coord.y);
+ TileOperand z_op = declare_tile_helper(writer, coord.z);
+ TileOperand batch_op = declare_tile_helper(writer, coord.batch);
+ TileOperand dil_x_op = declare_tile_helper(writer, dilations.dilation_x);
+ TileOperand dil_y_op = declare_tile_helper(writer, dilations.dilation_y);
+
+ TensorShape tensor_shape {10, 10, 10, 10};
+ TensorInfo tensor_info(tile_info.data_type(), tensor_shape, TensorDataLayout::Nhwc, 0 /* id */);
+ TensorOperand tensor_op = writer.declare_tensor_argument("tensor", tensor_info);
+ TensorSampler sampler(storage, sampler_data.format, sampler_data.mode_x, sampler_data.mode_y, sampler_data.mode_z);
+
+ const bool no_dilation = (dilations.dilation_x == "1" && dilations.dilation_y == "1");
+
+ writer.start_capture_code();
+ if(op == MemoryOperation::Load)
+ {
+ if(no_dilation)
+ {
+ writer.op_load(tile_op, tensor_op, sampler, x_op, y_op, z_op, batch_op);
+ }
+ else
+ {
+ writer.op_load_dilated(tile_op, tensor_op, sampler, x_op, y_op, z_op, batch_op, dil_x_op, dil_y_op);
+ }
+ }
+ else
+ {
+ if(no_dilation)
+ {
+ writer.op_store(tensor_op, tile_op, sampler, x_op, y_op, z_op, batch_op);
+ }
+ else
+ {
+ writer.op_store_dilated(tensor_op, tile_op, sampler, x_op, y_op, z_op, batch_op, dil_x_op, dil_y_op);
+ }
+ }
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_idx++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterOpLoadStoreTest";
+ }
+
+private:
+ std::vector<CLKernelWriterOpLoadStoreConfig> _configs {};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITEROPLOADSTORETEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterPrintTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterPrintTest.h
new file mode 100644
index 0000000000..6229dfb8c0
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterPrintTest.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERPRINT_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERPRINT_H
+
+#include "ckw/TileInfo.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+namespace ckw
+{
+
+class CLKernelWriterPrintTest : public ITest
+{
+public:
+ CLKernelWriterPrintTest()
+ {
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ const auto tile2x3f16 = writer.declare_tile("tile2x3f16", TileInfo(DataType::Fp16, 2, 3));
+ const auto tile1x2i32 = writer.declare_tile("tile1x2i32", TileInfo(DataType::Int32, 1, 2));
+ const auto tile2x1s32 = writer.declare_tile("tile2x1s32", TileInfo(DataType::Int32, 2, 1));
+ const auto tile1x1u32 = writer.declare_tile("tile1x1u32", TileInfo(DataType::Uint32, 1, 1));
+
+ writer.start_capture_code();
+
+ writer.op_print("debug_log", { tile2x3f16, tile1x2i32, tile2x1s32, tile1x1u32 });
+
+ constexpr auto expected_code =
+ "printf(\"debug_log\\nG0__tile2x3f16 = [[%v3hg], [%v3hg]]\\nG0__tile1x2i32 = [%v2hli]\\nG0__tile2x1s32 = [%i, %i]\\nG0__tile1x1u32 = %u\\n\", "
+ "G0__tile2x3f16__0, G0__tile2x3f16__1, G0__tile1x2i32, G0__tile2x1s32__0, G0__tile2x1s32__1, G0__tile1x1u32);\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, 0);
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterPrintTest";
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERPRINT_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterReturnTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterReturnTest.h
new file mode 100644
index 0000000000..fc3f2a639b
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterReturnTest.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERRETURNTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERRETURNTEST_H
+
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+namespace ckw
+{
+
+class CLKernelWriterReturnTest : public ITest
+{
+public:
+ CLKernelWriterReturnTest()
+ {
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ writer.start_capture_code();
+
+ writer.op_return();
+
+ constexpr auto expected_code = "return;\n";
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, 0);
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterReturnTest";
+ }
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERRETURNTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterSubTileTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterSubTileTest.h
new file mode 100644
index 0000000000..ea360b289e
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterSubTileTest.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_SRC_TESTS_CLKERNELWRITERSUBTILETEST_H
+#define CKW_VALIDATION_SRC_TESTS_CLKERNELWRITERSUBTILETEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "ckw/types/Operators.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterSubTileTest : public ITest
+{
+public:
+ CLKernelWriterSubTileTest()
+ {
+ // These are the definitions of the tiles involving in the writing actions.
+ //
+ // Structure:
+ // * List of tiles:
+ // - Tile full height.
+ // - Tile full width.
+ // - Tile view access type (full tile, vector, scalar).
+ // - Tile view start row.
+ // - Tile view start column.
+ // - The tile name.
+
+ // Vector access.
+ _tests.push_back(
+ { { { 1, 4, AccessType::Vector, 0, 0, "{tile_name}" }, //
+ { 4, 4, AccessType::Vector, 2, 0, "{tile_name}__2" },
+ { 1, 4, AccessType::Full, 0, 0, "{tile_name}" },
+ { 4, 4, AccessType::Vector, 3, 0, "{tile_name}__3" } } });
+
+ // Scalar access.
+ _tests.push_back(
+ { { { 1, 1, AccessType::Full, 0, 0, "{tile_name}" }, //
+ { 4, 8, AccessType::Scalar, 2, 4, "{tile_name}__2.s4" },
+ { 1, 16, AccessType::ScalarOfVector, 0, 10, "{tile_name}.sA" },
+ { 1, 1, AccessType::Scalar, 0, 0, "{tile_name}" } } });
+
+ // These are the definitions of the writing actions.
+ //
+ // Structure:
+ // * Writing function.
+ // * Whether this function only works with scalar value.
+ // * Expected code format.
+
+ _actions.push_back(
+ { [](CLKernelWriter &writer, const std::vector<TileOperand> &args)
+ {
+ writer.op_assign(args.at(0), args.at(1));
+ },
+ false,
+ "{op0} = {op1};\n" });
+
+ _actions.push_back(
+ { [](CLKernelWriter &writer, const std::vector<TileOperand> &args)
+ {
+ writer.op_unary(args.at(0), UnaryOp::Sqrt, args.at(1));
+ },
+ false,
+ "{op0} = sqrt({op1});\n" });
+
+ _actions.push_back(
+ { [](CLKernelWriter &writer, const std::vector<TileOperand> &args)
+ {
+ writer.op_binary(args.at(0), BinaryOp::Add, args.at(1), args.at(2));
+ },
+ false,
+ "{op0} = {op1} + {op2};\n" });
+
+ _actions.push_back(
+ { [](CLKernelWriter &writer, const std::vector<TileOperand> &args)
+ {
+ writer.op_ternary(args.at(0), TernaryOp::Clamp, args.at(1), args.at(2), args.at(3));
+ },
+ false,
+ "{op0} = clamp({op1}, {op2}, {op3});\n" });
+
+ _actions.push_back(
+ { [](CLKernelWriter &writer, const std::vector<TileOperand> &args)
+ {
+ writer.op_if(args.at(0), BinaryOp::Greater, args.at(1), [] {});
+ },
+ true,
+ "if ({op0} > {op1})\n{\n}\n" });
+ }
+
+ bool run() override
+ {
+ bool all_tests_passed = true;
+ int32_t test_idx = 0;
+
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ for(size_t test_no = 0; test_no < _tests.size(); ++test_no)
+ {
+ const TestInfo &test = _tests.at(test_no);
+
+ // Declare all the tiles and get the full name of those tile operand.
+ std::vector<TileOperand> tiles;
+ std::vector<std::string> expected_tiles_name;
+
+ for(size_t operand_no = 0; operand_no < test.operands.size(); ++operand_no)
+ {
+ const TestOperand &operand = test.operands.at(operand_no);
+ std::string name = "test" + std::to_string(test_no) + "_op" + std::to_string(operand_no);
+
+ const TileOperand full_tile = writer.declare_tile(name, TileInfo(DataType::Fp32, operand.height, operand.width));
+
+ switch(operand.access_type)
+ {
+ case AccessType::Full:
+ tiles.emplace_back(full_tile);
+ break;
+
+ case AccessType::Vector:
+ tiles.emplace_back(full_tile.row(operand.start_row));
+ break;
+
+ case AccessType::Scalar:
+ tiles.emplace_back(full_tile.scalar(operand.start_row, operand.start_col));
+ break;
+
+ case AccessType::ScalarOfVector:
+ tiles.emplace_back(full_tile.row(operand.start_row).scalar(0, operand.start_col));
+ break;
+
+ default:
+ CKW_THROW_MSG("Unsupported access type!");
+ }
+
+ expected_tiles_name.push_back("G0__" + name);
+ }
+
+ // Try each writing action using the newly declared tiles.
+ for(const TestAction &action : _actions)
+ {
+ if(action.scalar_only && //
+ (test.operands.at(0).access_type != AccessType::Scalar && //
+ (test.operands.at(0).height != 1 || test.operands.at(0).width != 1)))
+ {
+ continue;
+ }
+
+ writer.start_capture_code();
+
+ action.write(writer, tiles);
+
+ // The expected code is constructed from the format strings.
+ std::string expected_code = action.expected_code;
+
+ for(size_t operand_no = 0; operand_no < test.operands.size(); ++operand_no)
+ {
+ const TestOperand &operand = test.operands.at(operand_no);
+
+ const std::string op_name = search_and_replace(operand.name, "{tile_name}", expected_tiles_name.at(operand_no));
+ expected_code = search_and_replace(expected_code, "{op" + std::to_string(operand_no) + "}", op_name);
+ }
+
+ VALIDATE_TEST(writer.check_added_code(expected_code), all_tests_passed, test_idx++);
+ }
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string search_and_replace(const std::string &src, const std::string &search, const std::string &replace)
+ {
+ std::string result = src;
+
+ size_t idx = 0;
+
+ while(true)
+ {
+ idx = result.find(search, idx);
+
+ if(idx == std::string::npos)
+ {
+ break;
+ }
+
+ result = result.replace(idx, search.size(), replace);
+ }
+
+ return result;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterSubTileTest";
+ }
+
+private:
+ enum class AccessType
+ {
+ Full,
+ Vector,
+ Scalar,
+ ScalarOfVector,
+ };
+
+ struct TestOperand
+ {
+ int32_t height;
+ int32_t width;
+
+ AccessType access_type;
+ int32_t start_row;
+ int32_t start_col;
+
+ std::string name;
+ };
+
+ struct TestInfo
+ {
+ std::vector<TestOperand> operands;
+ };
+
+ struct TestAction
+ {
+ std::function<void(CLKernelWriter &, const std::vector<TileOperand> &)> write;
+
+ bool scalar_only;
+ std::string expected_code;
+ };
+
+ std::vector<TestInfo> _tests{};
+ std::vector<TestAction> _actions{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_SRC_TESTS_CLKERNELWRITERSUBTILETEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterTernaryOpTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterTernaryOpTest.h
new file mode 100644
index 0000000000..d25d3e2958
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterTernaryOpTest.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERTERNARYOPTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERTERNARYOPTEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "ckw/types/Operators.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterTernaryOpTest : public ITest
+{
+public:
+ CLKernelWriterTernaryOpTest()
+ {
+ // dst_height, dst_width, op0_height, op0_width, op1_height, op1_width, op2_height, op2_width, data_type, op, expected_code
+
+ _tests.push_back({ 1, 1, 1, 1, 1, 1, 1, 1, DataType::Fp32, TernaryOp::Select, "G0__dst = select(G0__op0, G0__op1, G0__op2);\n" }); // Scalar.
+
+ _tests.push_back({ 1, 3, 1, 3, 1, 3, 1, 3, DataType::Fp16, TernaryOp::Clamp, "G0__dst = clamp(G0__op0, G0__op1, G0__op2);\n" }); // Whole vector.
+
+ _tests.push_back({ 2, 4, 2, 4, 2, 4, 2, 4, DataType::Int8, TernaryOp::Select, "G0__dst__0 = select(G0__op0__0, G0__op1__0, G0__op2__0);\nG0__dst__1 = select(G0__op0__1, G0__op1__1, G0__op2__1);\n" }); // Whole tile.
+
+ _tests.push_back({ 2, 3, 1, 3, 2, 3, 2, 3, DataType::Uint8, TernaryOp::Clamp, "G0__dst__0 = clamp(G0__op0, G0__op1__0, G0__op2__0);\nG0__dst__1 = clamp(G0__op0, G0__op1__1, G0__op2__1);\n" }); // 1st operand y-dimension broadcast.
+
+ _tests.push_back({ 2, 3, 2, 3, 2, 1, 2, 3, DataType::Fp32, TernaryOp::Select, "G0__dst__0 = select(G0__op0__0, (float3)G0__op1__0, G0__op2__0);\nG0__dst__1 = select(G0__op0__1, (float3)G0__op1__1, G0__op2__1);\n" }); // 2nd operand x-dimension broadcast.
+
+ _tests.push_back({ 2, 3, 1, 3, 2, 1, 1, 1, DataType::Fp16, TernaryOp::Clamp, "G0__dst__0 = clamp(G0__op0, (half3)G0__op1__0, (half3)G0__op2);\nG0__dst__1 = clamp(G0__op0, (half3)G0__op1__1, (half3)G0__op2);\n" }); // 1st operand y-, 2nd operand x-, 3rd operand x- and y-dimension broadcast.
+ }
+
+ bool run() override
+ {
+ int32_t test_no = 0;
+ bool all_tests_passed = true;
+
+ for(const auto &test : _tests)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto dst = writer.declare_tile("dst", TileInfo(test.data_type, test.dst_height, test.dst_width));
+ auto op0 = writer.declare_tile("op0", TileInfo(DataType::Bool, test.op0_height, test.op0_width));
+ auto op1 = writer.declare_tile("op1", TileInfo(test.data_type, test.op1_height, test.op1_width));
+ auto op2 = writer.declare_tile("op2", TileInfo(test.data_type, test.op2_height, test.op2_width));
+
+ writer.start_capture_code();
+
+ writer.op_ternary(dst, test.op, op0, op1, op2);
+
+ VALIDATE_TEST(writer.check_added_code(test.expected_code), all_tests_passed, test_no++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterTernaryOpTest";
+ }
+
+private:
+ struct TestInfo
+ {
+ int32_t dst_height;
+ int32_t dst_width;
+ int32_t op0_height;
+ int32_t op0_width;
+ int32_t op1_height;
+ int32_t op1_width;
+ int32_t op2_height;
+ int32_t op2_width;
+ DataType data_type;
+ TernaryOp op;
+ std::string expected_code;
+ };
+
+ std::vector<TestInfo> _tests{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERTERNARYOPTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLKernelWriterUnaryExpressionTest.h b/compute_kernel_writer/validation/tests/CLKernelWriterUnaryExpressionTest.h
new file mode 100644
index 0000000000..395a2fe817
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLKernelWriterUnaryExpressionTest.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLKERNELWRITERUNARYEXPRESSIONTEST_H
+#define CKW_VALIDATION_TESTS_CLKERNELWRITERUNARYEXPRESSIONTEST_H
+
+#include "ckw/TileInfo.h"
+#include "ckw/types/DataType.h"
+#include "ckw/types/Operators.h"
+#include "src/cl/CLKernelWriter.h"
+#include "validation/tests/common/Common.h"
+#include "validation/tests/common/KernelWriterInterceptor.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace ckw
+{
+
+class CLKernelWriterUnaryExpressionTest : public ITest
+{
+public:
+ CLKernelWriterUnaryExpressionTest()
+ {
+ // dst_height, dst_width, src_height, src_width, data_type, op, expected_code
+
+ _tests.push_back({ 1, 1, 1, 1, DataType::Uint32, UnaryOp::BitwiseNot, "G0__dst = ~G0__src;\n" }); // Scalar.
+
+ _tests.push_back({ 1, 3, 1, 3, DataType::Int16, UnaryOp::LogicalNot, "G0__dst = !G0__src;\n" }); // Whole vector.
+
+ _tests.push_back({ 2, 4, 2, 4, DataType::Int8, UnaryOp::Exp, "G0__dst__0 = exp(G0__src__0);\nG0__dst__1 = exp(G0__src__1);\n" }); // Whole tile.
+
+ _tests.push_back({ 2, 3, 1, 3, DataType::Uint8, UnaryOp::Log, "G0__dst__0 = log(G0__src);\nG0__dst__1 = log(G0__src);\n" }); // Y-dimension broadcast.
+
+ _tests.push_back({ 2, 4, 2, 1, DataType::Uint16, UnaryOp::Sqrt, "G0__dst__0 = (ushort4)sqrt(G0__src__0);\nG0__dst__1 = (ushort4)sqrt(G0__src__1);\n" }); // X-dimension broadcast.
+
+ _tests.push_back({ 2, 3, 1, 1, DataType::Int32, UnaryOp::Round, "G0__dst__0 = (int3)round(G0__src);\nG0__dst__1 = (int3)round(G0__src);\n" }); // X and y dimension broadcast.
+ }
+
+ bool run() override
+ {
+ int32_t test_no = 0;
+ bool all_tests_passed = true;
+
+ for(const auto &test : _tests)
+ {
+ KernelWriterInterceptor<CLKernelWriter> writer;
+
+ auto dst = writer.declare_tile("dst", TileInfo(test.data_type, test.dst_height, test.dst_width));
+ auto src = writer.declare_tile("src", TileInfo(test.data_type, test.src_height, test.src_width));
+
+ writer.start_capture_code();
+
+ writer.op_unary(dst, test.op, src);
+
+ VALIDATE_TEST(writer.check_added_code(test.expected_code), all_tests_passed, test_no++);
+ }
+
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLKernelWriterUnaryExpressionTest";
+ }
+
+private:
+ struct TestInfo
+ {
+ int32_t dst_height;
+ int32_t dst_width;
+ int32_t src_height;
+ int32_t src_width;
+ DataType data_type;
+ UnaryOp op;
+ std::string expected_code;
+ };
+
+ std::vector<TestInfo> _tests{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLKERNELWRITERUNARYEXPRESSIONTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLTensorArgumentTest.h b/compute_kernel_writer/validation/tests/CLTensorArgumentTest.h
new file mode 100644
index 0000000000..d3e455cb83
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLTensorArgumentTest.h
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLTENSORARGUMENTTEST_H
+#define CKW_VALIDATION_TESTS_CLTENSORARGUMENTTEST_H
+
+#include "common/Common.h"
+#include "src/cl/CLHelpers.h"
+#include "src/cl/CLTensorArgument.h"
+#include "src/cl/CLTensorComponent.h"
+
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+class CLTensorArgumentComponentNamesTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentComponentNamesTest()
+ {
+ _components.push_back(TensorComponentType::Dim0);
+ _components.push_back(TensorComponentType::Dim1);
+ _components.push_back(TensorComponentType::Dim2);
+ _components.push_back(TensorComponentType::Dim3);
+ _components.push_back(TensorComponentType::Dim4);
+ _components.push_back(TensorComponentType::Dim1xDim2);
+ _components.push_back(TensorComponentType::Dim2xDim3);
+ _components.push_back(TensorComponentType::OffsetFirstElement);
+ _components.push_back(TensorComponentType::Stride0);
+ _components.push_back(TensorComponentType::Stride1);
+ _components.push_back(TensorComponentType::Stride2);
+ _components.push_back(TensorComponentType::Stride3);
+ _components.push_back(TensorComponentType::Stride4);
+
+ _expected_vars.push_back("src_dim0");
+ _expected_vars.push_back("src_dim1");
+ _expected_vars.push_back("src_dim2");
+ _expected_vars.push_back("src_dim3");
+ _expected_vars.push_back("src_dim4");
+ _expected_vars.push_back("src_dim1xdim2");
+ _expected_vars.push_back("src_dim2xdim3");
+ _expected_vars.push_back("src_offset_first_element");
+ _expected_vars.push_back("src_stride0");
+ _expected_vars.push_back("src_stride1");
+ _expected_vars.push_back("src_stride2");
+ _expected_vars.push_back("src_stride3");
+ _expected_vars.push_back("src_stride4");
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_components.size() == _expected_vars.size(), "The number of components and variables does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_tests = _expected_vars.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_tests; ++i)
+ {
+ CLTensorArgument arg(tensor_name, info, false /* return_dims_by_value */);
+
+ const std::string expected_var_name = _expected_vars[i];
+ const std::string actual_var_name = arg.component(_components[i]).name();
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentVariableNamesTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _components{};
+ std::vector<std::string> _expected_vars{};
+};
+
+class CLTensorArgumentStorageNamesTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentStorageNamesTest()
+ {
+ _storages.push_back(TensorStorageType::BufferUint8Ptr);
+ _storages.push_back(TensorStorageType::Texture2dReadOnly);
+ _storages.push_back(TensorStorageType::Texture2dWriteOnly);
+
+ _expected_vars.push_back("src_ptr");
+ _expected_vars.push_back("src_img2d");
+ _expected_vars.push_back("src_img2d");
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_storages.size() == _expected_vars.size(), "The number of storages and variables does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_tests = _expected_vars.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_tests; ++i)
+ {
+ CLTensorArgument arg(tensor_name, info, false /* return_dims_by_value */);
+
+ const std::string expected_var_name = _expected_vars[i];
+ const std::string actual_var_name = arg.storage(_storages[i]).val;
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentStorageNamesTest";
+ }
+
+private:
+ std::vector<TensorStorageType> _storages{};
+ std::vector<std::string> _expected_vars{};
+};
+
+class CLTensorArgumentComponentValuesTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentComponentValuesTest()
+ {
+ _components.push_back(TensorComponentType::Dim0);
+ _components.push_back(TensorComponentType::Dim1);
+ _components.push_back(TensorComponentType::Dim2);
+ _components.push_back(TensorComponentType::Dim3);
+ _components.push_back(TensorComponentType::Dim4);
+ _components.push_back(TensorComponentType::Dim1xDim2);
+ _components.push_back(TensorComponentType::Dim2xDim3);
+
+ _expected_vals.push_back(std::to_string(shape[0]));
+ _expected_vals.push_back(std::to_string(shape[1]));
+ _expected_vals.push_back(std::to_string(shape[2]));
+ _expected_vals.push_back(std::to_string(shape[3]));
+ _expected_vals.push_back(std::to_string(shape[4]));
+ _expected_vals.push_back(std::to_string(shape[1] * shape[2]));
+ _expected_vals.push_back(std::to_string(shape[2] * shape[3]));
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_components.size() == _expected_vals.size(), "The number of components and values does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_tests = _expected_vals.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_tests; ++i)
+ {
+ CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */);
+
+ const std::string expected_var_val = std::string("((int)(") + _expected_vals[i] + "))";
+ const std::string actual_var_val = arg.cl_component(_components[i]).scalar(0, 0).str;
+
+ VALIDATE_TEST(actual_var_val.compare(expected_var_val) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentComponentValuesTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _components{};
+ std::vector<std::string> _expected_vals{};
+};
+
+class CLTensorArgumentComponentsUsedPassByValueFalseTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentComponentsUsedPassByValueFalseTest()
+ {
+ _components.push_back(TensorComponentType::Dim0);
+ _components.push_back(TensorComponentType::Dim2);
+ _components.push_back(TensorComponentType::Dim3);
+ _components.push_back(TensorComponentType::Dim1xDim2);
+ _components.push_back(TensorComponentType::OffsetFirstElement);
+ _components.push_back(TensorComponentType::Stride1);
+ _components.push_back(TensorComponentType::Stride2);
+ _components.push_back(TensorComponentType::Stride3);
+ _components.push_back(TensorComponentType::Dim0); // Repeat the query. The TensorArgument should not create a new variable
+ _components.push_back(TensorComponentType::Dim2); // Repeat the query. The TensorArgument should not create a new variable
+ _components.push_back(TensorComponentType::Dim3); // Repeat the query. The TensorArgument should not create a new variable
+
+ _expected_vars.push_back("src_dim0");
+ _expected_vars.push_back("src_dim2");
+ _expected_vars.push_back("src_dim3");
+ _expected_vars.push_back("src_dim1xdim2");
+ _expected_vars.push_back("src_offset_first_element");
+ _expected_vars.push_back("src_stride1");
+ _expected_vars.push_back("src_stride2");
+ _expected_vars.push_back("src_stride3");
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_components = _components.size();
+
+ int32_t test_idx = 0;
+
+ CLTensorArgument arg(tensor_name, info, false /* return_dims_by_value */);
+ for(size_t i = 0; i < num_components; ++i)
+ {
+ arg.component(_components[i]);
+ }
+
+ const auto actual_vars = arg.components();
+
+ const size_t num_vars = _expected_vars.size();
+
+ VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables");
+
+ for(size_t i = 0; i < num_vars; ++i)
+ {
+ // Validate variable name
+ const std::string expected_var_name = _expected_vars[i];
+ const std::string actual_var_name = actual_vars[i]->tile().name();
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+
+ // Validate data type
+ const DataType expected_var_type = DataType::Int32;
+ const DataType actual_var_type = actual_vars[i]->tile().info().data_type();
+ VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++);
+
+ // Validate tile shape
+ const int32_t actual_var_width = actual_vars[i]->tile().info().width();
+ const int32_t actual_var_height = actual_vars[i]->tile().info().height();
+
+ VALIDATE_TEST(actual_var_height == 1, all_tests_passed, test_idx++);
+ VALIDATE_TEST(actual_var_width == 1, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentComponentsUsedPassByValueFalseTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _components{};
+ std::vector<std::string> _expected_vars{};
+};
+
+class CLTensorArgumentComponentsUsedPassByValueTrueTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentComponentsUsedPassByValueTrueTest()
+ {
+ _components.push_back(TensorComponentType::Dim0);
+ _components.push_back(TensorComponentType::Dim2);
+ _components.push_back(TensorComponentType::Dim3);
+ _components.push_back(TensorComponentType::Dim1xDim2);
+ _components.push_back(TensorComponentType::OffsetFirstElement);
+ _components.push_back(TensorComponentType::Stride1);
+ _components.push_back(TensorComponentType::Stride2);
+ _components.push_back(TensorComponentType::Stride3);
+ _components.push_back(TensorComponentType::OffsetFirstElement); // Repeat the query. The TensorArgument should not create a new variable
+ _components.push_back(TensorComponentType::Stride1); // Repeat the query. The TensorArgument should not create a new variable
+
+ _expected_vars.push_back("src_offset_first_element");
+ _expected_vars.push_back("src_stride1");
+ _expected_vars.push_back("src_stride2");
+ _expected_vars.push_back("src_stride3");
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_components = _components.size();
+
+ int32_t test_idx = 0;
+
+ CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */);
+ for(size_t i = 0; i < num_components; ++i)
+ {
+ arg.component(_components[i]);
+ }
+
+ const auto actual_vars = arg.components();
+
+ const size_t num_vars = _expected_vars.size();
+
+ VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables");
+
+ // Since the dimensions are passed by value, we expect only the variables for the strides
+ for(size_t i = 0; i < num_vars; ++i)
+ {
+ // Validate variable name
+ const std::string expected_var_name = _expected_vars[i];
+ const std::string actual_var_name = actual_vars[i]->tile().name();
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+
+ // Validate data type
+ const DataType expected_var_type = DataType::Int32;
+ const DataType actual_var_type = actual_vars[i]->tile().info().data_type();
+ VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++);
+
+ // Validate tile shape
+ const int32_t actual_var_width = actual_vars[i]->tile().info().width();
+ const int32_t actual_var_height = actual_vars[i]->tile().info().height();
+
+ VALIDATE_TEST(actual_var_height == 1, all_tests_passed, test_idx++);
+ VALIDATE_TEST(actual_var_width == 1, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentComponentsUsedPassByValueTrueTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _components{};
+ std::vector<std::string> _expected_vars{};
+};
+
+class CLTensorArgumentStoragesUsedTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { 12, 14, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentStoragesUsedTest()
+ {
+ _storages.push_back(TensorStorageType::BufferUint8Ptr);
+ _storages.push_back(TensorStorageType::Texture2dReadOnly);
+ _storages.push_back(TensorStorageType::BufferUint8Ptr); // Repeat the query. The TensorArgument should not create a new variable
+
+ _expected_vars.push_back("src_ptr");
+ _expected_vars.push_back("src_img2d");
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_storages = _storages.size();
+
+ int32_t test_idx = 0;
+
+ CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */);
+ for(size_t i = 0; i < num_storages; ++i)
+ {
+ arg.storage(_storages[i]);
+ }
+
+ const auto actual_vars = arg.storages();
+
+ const size_t num_vars = _expected_vars.size();
+
+ VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables");
+
+ for(size_t i = 0; i < num_vars; ++i)
+ {
+ // Validate variable name
+ const std::string expected_var_name = _expected_vars[i];
+ const std::string actual_var_name = actual_vars[i].val;
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+
+ // Validate storage type
+ const auto expected_var_type = _storages[i];
+ const auto actual_var_type = actual_vars[i].type;
+ VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentStoragesUsedTest";
+ }
+
+private:
+ std::vector<TensorStorageType> _storages{};
+ std::vector<std::string> _expected_vars{};
+};
+
+class CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest : public ITest
+{
+public:
+ const DataType dt = DataType::Fp32;
+ const TensorShape shape = TensorShape({ { -1, -1, 3, 1, 2 } });
+ const std::string tensor_name = "src";
+
+ CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest()
+ {
+ _components.push_back(TensorComponentType::Dim0);
+ _components.push_back(TensorComponentType::Dim2);
+ _components.push_back(TensorComponentType::Dim3);
+ _components.push_back(TensorComponentType::Dim1xDim2);
+ _components.push_back(TensorComponentType::OffsetFirstElement);
+ _components.push_back(TensorComponentType::Stride1);
+ _components.push_back(TensorComponentType::Stride2);
+ _components.push_back(TensorComponentType::Stride3);
+ _components.push_back(TensorComponentType::OffsetFirstElement); // Repeat the query. The TensorArgument should not create a new variable
+ _components.push_back(TensorComponentType::Stride1); // Repeat the query. The TensorArgument should not create a new variable
+
+ _expected_vars.push_back("src_dim0");
+ _expected_vars.push_back("src_dim1xdim2");
+ _expected_vars.push_back("src_offset_first_element");
+ _expected_vars.push_back("src_stride1");
+ _expected_vars.push_back("src_stride2");
+ _expected_vars.push_back("src_stride3");
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TensorInfo info(dt, shape, TensorDataLayout::Nhwc, 1);
+
+ const size_t num_components = _components.size();
+
+ int32_t test_idx = 0;
+
+ CLTensorArgument arg(tensor_name, info, true /* return_dims_by_value */);
+ for(size_t i = 0; i < num_components; ++i)
+ {
+ arg.component(_components[i]);
+ }
+
+ const auto actual_vars = arg.components();
+
+ const size_t num_vars = _expected_vars.size();
+
+ VALIDATE_ON_MSG(actual_vars.size() == num_vars, "The number of variables must match the number of expected variables");
+
+ // Since the dimensions are passed by value, we expect only the variables for the strides
+ for(size_t i = 0; i < num_vars; ++i)
+ {
+ // Validate variable name
+ const std::string expected_var_name = _expected_vars[i];
+ const std::string actual_var_name = actual_vars[i]->tile().name();
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+
+ // Validate data type
+ const DataType expected_var_type = DataType::Int32;
+ const DataType actual_var_type = actual_vars[i]->tile().info().data_type();
+ VALIDATE_TEST(actual_var_type == expected_var_type, all_tests_passed, test_idx++);
+
+ // Validate tile shape
+ const int32_t actual_var_width = actual_vars[i]->tile().info().width();
+ const int32_t actual_var_height = actual_vars[i]->tile().info().height();
+
+ VALIDATE_TEST(actual_var_height == 1, all_tests_passed, test_idx++);
+ VALIDATE_TEST(actual_var_width == 1, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTensorArgumentComponentsUsedPassByValueTrueDynamicDimTrueTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _components{};
+ std::vector<std::string> _expected_vars{};
+};
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLTENSORARGUMENTTEST_H
diff --git a/compute_kernel_writer/validation/tests/CLTileTest.hpp b/compute_kernel_writer/validation/tests/CLTileTest.hpp
new file mode 100644
index 0000000000..a95a11ace7
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/CLTileTest.hpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_CLTILETEST_HPP
+#define CKW_VALIDATION_TESTS_CLTILETEST_HPP
+
+#include "common/Common.h"
+#include "src/Helpers.h"
+#include "src/cl/CLTile.h"
+
+#include <string>
+#include <vector>
+
+namespace ckw
+{
+class CLTileInternalVariableNamesTest : public ITest
+{
+public:
+ const int32_t width = 4;
+ const int32_t height = 4;
+ const DataType dt = DataType::Fp32;
+
+ CLTileInternalVariableNamesTest()
+ {
+ _tile_name.push_back("dst");
+ _tile_name.push_back("_G0_dst");
+ _tile_name.push_back("_SRC");
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const TileInfo info(dt, height, width);
+
+ int32_t test_idx = 0;
+ for(const auto &tile_name : _tile_name)
+ {
+ const CLTile tile(tile_name, info);
+ const auto vars = tile.all();
+
+ for(int32_t y = 0; y < height; ++y)
+ {
+ const std::string expected_var_name = tile_name + "__" + std::to_string(y);
+ const std::string actual_var_name = vars[y].str;
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileInternalVariableNamesTest";
+ }
+
+private:
+ std::vector<std::string> _tile_name{};
+};
+
+class CLTileInternalNumVariablesTest : public ITest
+{
+public:
+ CLTileInternalNumVariablesTest()
+ {
+ _width.push_back(4);
+ _width.push_back(1);
+ _width.push_back(16);
+
+ _height.push_back(1);
+ _height.push_back(5);
+ _height.push_back(3);
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_width.size() == _height.size(), "The number of widths and heights does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const size_t num_dims = _width.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_dims; ++i)
+ {
+ const int32_t width = _width[i];
+ const int32_t height = _height[i];
+ const TileInfo info(DataType::Fp32, height, width);
+ const CLTile tile("src", info);
+ const auto vars = tile.all();
+ const int32_t num_vars = vars.size();
+
+ // We expect the number of variables to match the heigth of the tile
+ VALIDATE_TEST(num_vars == height, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileInternalNumVariablesTest";
+ }
+
+private:
+ std::vector<int32_t> _width{};
+ std::vector<int32_t> _height{};
+};
+
+class CLTileAccessScalarVariableTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t width = 16;
+ const int32_t height = 8;
+ const DataType dt = DataType::Fp32;
+
+ CLTileAccessScalarVariableTest()
+ {
+ _x_coord.push_back(4);
+ _x_coord.push_back(1);
+ _x_coord.push_back(15);
+ _x_coord.push_back(10);
+
+ _y_coord.push_back(1);
+ _y_coord.push_back(5);
+ _y_coord.push_back(3);
+ _y_coord.push_back(4);
+ }
+
+ bool run() override
+ {
+ const TileInfo info(dt, height, width);
+ const CLTile tile(tile_name, info);
+
+ VALIDATE_ON_MSG(_x_coord.size() == _y_coord.size(), "The number of x-coords and y-coords does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const size_t num_coords = _x_coord.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_coords; ++i)
+ {
+ const int32_t x_coord = _x_coord[i];
+ const int32_t y_coord = _y_coord[i];
+
+ const TileVariable var = tile.scalar(y_coord, x_coord);
+
+ const std::string actual_var_name = var.str;
+ std::string expected_var_name = tile_name;
+ expected_var_name += "__" + std::to_string(y_coord);
+ expected_var_name += ".s" + dec_to_hex_as_string(x_coord);
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileAccessScalarVariableTest";
+ }
+
+private:
+ std::vector<int32_t> _x_coord{};
+ std::vector<int32_t> _y_coord{};
+};
+
+class CLTileAccessScalarVariableBroadcastXTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t height = 8;
+ const DataType dt = DataType::Fp32;
+
+ CLTileAccessScalarVariableBroadcastXTest()
+ {
+ _width.push_back(1);
+ _width.push_back(2);
+ _width.push_back(3);
+
+ _x_coord.push_back(4);
+ _x_coord.push_back(5);
+ _x_coord.push_back(6);
+
+ _y_coord.push_back(1);
+ _y_coord.push_back(3);
+ _y_coord.push_back(2);
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_width.size() == _y_coord.size(), "The number of widths and y-coords does not match");
+ VALIDATE_ON_MSG(_x_coord.size() == _y_coord.size(), "The number of x-coords and y-coords does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const size_t num_coords = _x_coord.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_coords; ++i)
+ {
+ const int32_t width = _width[i];
+ const int32_t x_coord = _x_coord[i];
+ const int32_t y_coord = _y_coord[i];
+
+ const int32_t x_coord_clamped = clamp(x_coord, static_cast<int32_t>(0), width - 1);
+
+ const TileInfo info(dt, height, width);
+ const CLTile tile(tile_name, info);
+
+ const TileVariable var = tile.scalar(y_coord, x_coord);
+
+ const std::string actual_var_name = var.str;
+ std::string expected_var_name = tile_name;
+ expected_var_name += "__" + std::to_string(y_coord);
+ if(width != 1)
+ {
+ expected_var_name += ".s" + dec_to_hex_as_string(x_coord_clamped);
+ }
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileAccessScalarVariableBroadcastXTest";
+ }
+
+private:
+ std::vector<int32_t> _width{};
+ std::vector<int32_t> _x_coord{};
+ std::vector<int32_t> _y_coord{};
+};
+
+class CLTileAccessScalarVariableBroadcastYTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t width = 8;
+ const DataType dt = DataType::Fp32;
+
+ CLTileAccessScalarVariableBroadcastYTest()
+ {
+ _height.push_back(1);
+ _height.push_back(2);
+ _height.push_back(3);
+
+ _x_coord.push_back(4);
+ _x_coord.push_back(5);
+ _x_coord.push_back(6);
+
+ _y_coord.push_back(3);
+ _y_coord.push_back(4);
+ _y_coord.push_back(5);
+ }
+
+ bool run() override
+ {
+ VALIDATE_ON_MSG(_height.size() == _y_coord.size(), "The number of widths and y-coords does not match");
+ VALIDATE_ON_MSG(_x_coord.size() == _y_coord.size(), "The number of x-coords and y-coords does not match");
+
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ const size_t num_coords = _x_coord.size();
+
+ int32_t test_idx = 0;
+ for(size_t i = 0; i < num_coords; ++i)
+ {
+ const int32_t height = _height[i];
+ const int32_t x_coord = _x_coord[i];
+ const int32_t y_coord = _y_coord[i];
+
+ const int32_t y_coord_clamped = clamp(y_coord, static_cast<int32_t>(0), height - 1);
+
+ const TileInfo info(dt, height, width);
+ const CLTile tile(tile_name, info);
+
+ const TileVariable var = tile.scalar(y_coord, x_coord);
+
+ const std::string actual_var_name = var.str;
+ std::string expected_var_name = tile_name;
+ if(height != 1)
+ {
+ expected_var_name += "__" + std::to_string(y_coord_clamped);
+ }
+
+ if(width != 1)
+ {
+ expected_var_name += ".s" + dec_to_hex_as_string(x_coord);
+ }
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileAccessScalarVariableBroadcastYTest";
+ }
+
+private:
+ std::vector<int32_t> _height{};
+ std::vector<int32_t> _x_coord{};
+ std::vector<int32_t> _y_coord{};
+};
+
+class CLTileAccessVectorVariablesTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t width = 8;
+ const DataType dt = DataType::Fp32;
+
+ CLTileAccessVectorVariablesTest()
+ {
+ _heights.push_back(1);
+ _heights.push_back(2);
+ _heights.push_back(3);
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ int32_t test_idx = 0;
+ for(const auto &height : _heights)
+ {
+ const TileInfo info(dt, height, width);
+ const CLTile tile(tile_name, info);
+
+ for(int32_t row = 0; row < height; ++row)
+ {
+ const TileVariable var = tile.vector(row);
+
+ const std::string actual_var_name = var.str;
+ std::string expected_var_name = tile_name;
+ if(height != 1)
+ {
+ expected_var_name += "__" + std::to_string(row);
+ }
+
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileAccessVectorVariablesTest";
+ }
+
+private:
+ std::vector<int32_t> _heights{};
+};
+
+class CLTileAccessSubVectorVariablesTest : public ITest
+{
+public:
+ const std::string tile_name = "src";
+ const int32_t width = 8;
+ const int32_t height = 3;
+ const DataType dt = DataType::Fp32;
+
+ CLTileAccessSubVectorVariablesTest()
+ {
+ _subwidths.push_back(1);
+ _subwidths.push_back(2);
+ _subwidths.push_back(3);
+ _subwidths.push_back(4);
+ _offsets.push_back(1);
+ _offsets.push_back(3);
+ _offsets.push_back(4);
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ size_t test_idx = 0;
+
+ for(auto &col_start : _offsets)
+ {
+ for(const auto &subwidth : _subwidths)
+ {
+ const TileInfo info(dt, height, width);
+ const CLTile tile(tile_name, info);
+
+ for(int32_t row = 0; row < height; ++row)
+ {
+ std::string expected_var_name = tile_name;
+ if(height != 1)
+ {
+ expected_var_name += "__" + std::to_string(row);
+ }
+
+ if(width != 1)
+ {
+ expected_var_name += ".s";
+ }
+
+ int32_t col = col_start;
+ for(; col < col_start + subwidth - 1; ++col)
+ {
+ if(width != 1)
+ {
+ expected_var_name += dec_to_hex_as_string(col);
+ }
+ }
+
+ if(width != 1)
+ {
+ expected_var_name += dec_to_hex_as_string(col);
+ }
+
+ const std::string actual_var_name = tile.vector(row, col_start, subwidth).str;
+ VALIDATE_TEST(actual_var_name.compare(expected_var_name) == 0, all_tests_passed, test_idx++);
+ }
+ }
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "CLTileAccessSubVectorVariablesTest";
+ }
+
+private:
+ std::vector<int32_t> _subwidths{};
+ std::vector<int32_t> _offsets{};
+};
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_CLTILETEST_HPP
diff --git a/compute_kernel_writer/validation/tests/TensorBitMaskTest.h b/compute_kernel_writer/validation/tests/TensorBitMaskTest.h
new file mode 100644
index 0000000000..759d926d18
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/TensorBitMaskTest.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef CKW_TESTS_TENSORBITMASKTEST_H
+#define CKW_TESTS_TENSORBITMASKTEST_H
+
+#include "ckw/TensorInfo.h"
+#include "ckw/types/TensorComponentType.h"
+#include "common/Common.h"
+#include "src/types/TensorComponentType.h"
+
+#include <vector>
+
+namespace ckw
+{
+class TensorBitMaskTrueTest : public ITest
+{
+public:
+ TensorBitMaskTrueTest()
+ {
+ _component.push_back(TensorComponentType::Dim0);
+ _component.push_back(TensorComponentType::Dim1);
+ _component.push_back(TensorComponentType::Dim2);
+ _component.push_back(TensorComponentType::Dim3);
+ _component.push_back(TensorComponentType::Dim4);
+ _component.push_back(TensorComponentType::Stride0);
+ _component.push_back(TensorComponentType::Stride1);
+ _component.push_back(TensorComponentType::Stride2);
+ _component.push_back(TensorComponentType::Stride3);
+ _component.push_back(TensorComponentType::Stride4);
+ _component.push_back(TensorComponentType::Dim1xDim2);
+ _component.push_back(TensorComponentType::Dim1xDim2xDim3);
+ _component.push_back(TensorComponentType::Dim2xDim3);
+ _component.push_back(TensorComponentType::OffsetFirstElement);
+
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ VALIDATE_ON_MSG(_component.size() == _bitmask.size(),
+ "The number of layouts and components does not match");
+ const size_t num_tests = _component.size();
+ for(size_t i = 0; i < num_tests; ++i)
+ {
+ const TensorComponentType component = _component[i];
+ const TensorComponentBitmask bitmask = _bitmask[i];
+ const bool out = static_cast<uint32_t>(component) & static_cast<uint32_t>(bitmask);
+ VALIDATE_TEST(out == true, all_tests_passed, i);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "TensorBitMaskTrueTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _component{};
+ std::vector<TensorComponentBitmask> _bitmask{};
+};
+
+class TensorBitMaskFalseTest : public ITest
+{
+public:
+ TensorBitMaskFalseTest()
+ {
+ _component.push_back(TensorComponentType::Dim0);
+ _component.push_back(TensorComponentType::Dim1);
+ _component.push_back(TensorComponentType::Dim2);
+ _component.push_back(TensorComponentType::Dim3);
+ _component.push_back(TensorComponentType::Dim4);
+ _component.push_back(TensorComponentType::Dim0);
+ _component.push_back(TensorComponentType::Dim1);
+ _component.push_back(TensorComponentType::Dim2);
+ _component.push_back(TensorComponentType::Dim3);
+ _component.push_back(TensorComponentType::Dim4);
+ _component.push_back(TensorComponentType::Dim0);
+ _component.push_back(TensorComponentType::Dim1);
+ _component.push_back(TensorComponentType::Dim2);
+ _component.push_back(TensorComponentType::Dim3);
+ _component.push_back(TensorComponentType::Dim4);
+ _component.push_back(TensorComponentType::Stride0);
+ _component.push_back(TensorComponentType::Stride1);
+ _component.push_back(TensorComponentType::Stride2);
+ _component.push_back(TensorComponentType::Stride3);
+ _component.push_back(TensorComponentType::Stride4);
+ _component.push_back(TensorComponentType::Stride0);
+ _component.push_back(TensorComponentType::Stride1);
+ _component.push_back(TensorComponentType::Stride2);
+ _component.push_back(TensorComponentType::Stride3);
+ _component.push_back(TensorComponentType::Stride4);
+ _component.push_back(TensorComponentType::Stride0);
+ _component.push_back(TensorComponentType::Stride1);
+ _component.push_back(TensorComponentType::Stride2);
+ _component.push_back(TensorComponentType::Stride3);
+ _component.push_back(TensorComponentType::Stride4);
+ _component.push_back(TensorComponentType::Dim1xDim2);
+ _component.push_back(TensorComponentType::Dim1xDim2xDim3);
+ _component.push_back(TensorComponentType::Dim2xDim3);
+ _component.push_back(TensorComponentType::Dim1xDim2);
+ _component.push_back(TensorComponentType::Dim1xDim2xDim3);
+ _component.push_back(TensorComponentType::Dim2xDim3);
+ _component.push_back(TensorComponentType::Dim1xDim2);
+ _component.push_back(TensorComponentType::Dim1xDim2xDim3);
+ _component.push_back(TensorComponentType::Dim2xDim3);
+ _component.push_back(TensorComponentType::OffsetFirstElement);
+ _component.push_back(TensorComponentType::OffsetFirstElement);
+ _component.push_back(TensorComponentType::OffsetFirstElement);
+
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::OffsetFirstElement);
+ _bitmask.push_back(TensorComponentBitmask::Dimension);
+ _bitmask.push_back(TensorComponentBitmask::Stride);
+ _bitmask.push_back(TensorComponentBitmask::FoldedDimensions);
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ VALIDATE_ON_MSG(_component.size() == _bitmask.size(),
+ "The number of layouts and components does not match");
+ const size_t num_tests = _component.size();
+ for(size_t i = 0; i < num_tests; ++i)
+ {
+ const TensorComponentType component = _component[i];
+ const TensorComponentBitmask bitmask = _bitmask[i];
+ const bool out = static_cast<uint32_t>(component) & static_cast<uint32_t>(bitmask);
+ VALIDATE_TEST(out == false, all_tests_passed, i);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "TensorBitMaskFalseTest";
+ }
+
+private:
+ std::vector<TensorComponentType> _component{};
+ std::vector<TensorComponentBitmask> _bitmask{};
+};
+} // namespace ckw
+
+#endif // CKW_TESTS_TENSORBITMASKTEST_H
diff --git a/compute_kernel_writer/validation/tests/UtilsTest.h b/compute_kernel_writer/validation/tests/UtilsTest.h
new file mode 100644
index 0000000000..a335a48f81
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/UtilsTest.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef CKW_TESTS_UTILSTEST_H
+#define CKW_TESTS_UTILSTEST_H
+
+#include "ckw/TensorInfo.h"
+#include "ckw/types/TensorDataLayout.h"
+#include "common/Common.h"
+#include "src/TensorUtils.h"
+
+#include <vector>
+
+namespace ckw
+{
+class UtilsTest : public ITest
+{
+public:
+ UtilsTest()
+ {
+ _layout.push_back(TensorDataLayout::Nhwc);
+ _layout.push_back(TensorDataLayout::Nhwc);
+ _layout.push_back(TensorDataLayout::Nhwc);
+ _layout.push_back(TensorDataLayout::Nhwc);
+ _layout.push_back(TensorDataLayout::Ndhwc);
+ _layout.push_back(TensorDataLayout::Ndhwc);
+ _layout.push_back(TensorDataLayout::Ndhwc);
+ _layout.push_back(TensorDataLayout::Ndhwc);
+ _layout.push_back(TensorDataLayout::Ndhwc);
+
+ _component.push_back(TensorDataLayoutComponent::N);
+ _component.push_back(TensorDataLayoutComponent::H);
+ _component.push_back(TensorDataLayoutComponent::W);
+ _component.push_back(TensorDataLayoutComponent::C);
+ _component.push_back(TensorDataLayoutComponent::N);
+ _component.push_back(TensorDataLayoutComponent::D);
+ _component.push_back(TensorDataLayoutComponent::H);
+ _component.push_back(TensorDataLayoutComponent::W);
+ _component.push_back(TensorDataLayoutComponent::C);
+
+ _expected.push_back(TensorComponentType::Dim3);
+ _expected.push_back(TensorComponentType::Dim2);
+ _expected.push_back(TensorComponentType::Dim1);
+ _expected.push_back(TensorComponentType::Dim0);
+ _expected.push_back(TensorComponentType::Dim4);
+ _expected.push_back(TensorComponentType::Dim3);
+ _expected.push_back(TensorComponentType::Dim2);
+ _expected.push_back(TensorComponentType::Dim1);
+ _expected.push_back(TensorComponentType::Dim0);
+ }
+
+ bool run() override
+ {
+ // The status of this variable can change in VALIDATE_TEST()
+ bool all_tests_passed = true;
+
+ VALIDATE_ON_MSG(_layout.size() == _component.size(), "The number of layouts and components does not match");
+ VALIDATE_ON_MSG(_layout.size() == _expected.size(),
+ "The number of layouts and expected outputs does not match");
+ const size_t num_tests = _layout.size();
+ for(size_t i = 0; i < num_tests; ++i)
+ {
+ const TensorDataLayout layout = _layout[i];
+ const TensorDataLayoutComponent component = _component[i];
+ const TensorComponentType expected = _expected[i];
+ const TensorComponentType out = get_tensor_dimension(layout, component);
+ VALIDATE_TEST(out == expected, all_tests_passed, i);
+ }
+ return all_tests_passed;
+ }
+
+ std::string name() override
+ {
+ return "UtilsTest";
+ }
+
+private:
+ std::vector<TensorDataLayout> _layout{};
+ std::vector<TensorDataLayoutComponent> _component{};
+ std::vector<TensorComponentType> _expected{};
+};
+} // namespace ckw
+
+#endif // CKW_TESTS_UTILSTEST_H
diff --git a/compute_kernel_writer/validation/tests/common/Common.h b/compute_kernel_writer/validation/tests/common/Common.h
new file mode 100644
index 0000000000..8573c42b88
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/common/Common.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+#ifndef COMPUTE_KERNEL_WRITER_TEST_COMMON_COMMON_H
+#define COMPUTE_KERNEL_WRITER_TEST_COMMON_COMMON_H
+
+#include <cassert>
+#include <iostream>
+#include <string>
+
+namespace ckw
+{
+#define VALIDATE_ON_MSG(exp, msg) assert(((void)msg, exp))
+
+#define VALIDATE_TEST(exp, all_tests_passed, id_test) \
+ do \
+ { \
+ if((exp) == true) \
+ { \
+ all_tests_passed &= true; \
+ const std::string msg = "TEST " + std::to_string((id_test)) + ": [PASSED]"; \
+ std::cout << msg << std::endl; \
+ } \
+ else \
+ { \
+ all_tests_passed &= false; \
+ const std::string msg = "TEST " + std::to_string((id_test)) + ": [FAILED]"; \
+ std::cout << msg << std::endl; \
+ } \
+ } while(false)
+
+class ITest
+{
+public:
+ virtual ~ITest() = default;
+
+ /** Method to run the test
+ *
+ * @return it returns true if all tests passed
+ */
+ virtual bool run() = 0;
+
+ /** Name of the test
+ *
+ * @return it returns the name of the test
+ */
+ virtual std::string name() = 0;
+};
+} // namespace ckw
+
+#endif /* COMPUTE_KERNEL_WRITER_TEST_COMMON_COMMON_H */
diff --git a/compute_kernel_writer/validation/tests/common/KernelWriterInterceptor.h b/compute_kernel_writer/validation/tests/common/KernelWriterInterceptor.h
new file mode 100644
index 0000000000..89bb76e37f
--- /dev/null
+++ b/compute_kernel_writer/validation/tests/common/KernelWriterInterceptor.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#ifndef CKW_VALIDATION_TESTS_COMMON_KERNELWRITERINTERCEPTOR_H
+#define CKW_VALIDATION_TESTS_COMMON_KERNELWRITERINTERCEPTOR_H
+
+#include <string>
+#include <utility>
+
+namespace ckw
+{
+
+/** This class provides the ability to capture only the code changed after a point
+ * and compares that part of code with the expected value.
+ *
+ * It is useful for testing purpose when a particular sequence of instructions is interested
+ * while the rest of the initialization code is out of scope.
+ */
+template <typename T>
+class KernelWriterInterceptor : public T
+{
+public:
+ template <typename... TArgs>
+ KernelWriterInterceptor(const TArgs &&...args)
+ : T(std::forward<TArgs>(args)...)
+ {
+ }
+
+ /** Mark this point in the source code as the start position to capture.
+ * Only source code added after this function is considered when check_add_code is called.
+ */
+ void start_capture_code()
+ {
+ _start_code = this->body_source_code();
+ }
+
+ /** Compare the source code added after start_capture_code is called the the specified expected code. */
+ bool check_added_code(const std::string &expected_added_code)
+ {
+ const auto &end_code = this->body_source_code();
+
+ // Code can only grow over time.
+ if(end_code.length() < _start_code.length())
+ {
+ return false;
+ }
+
+ // New code must be added to the source code without changing the already existed code.
+ if(end_code.substr(0, _start_code.length()) != _start_code)
+ {
+ return false;
+ }
+
+ // The newly added code must match the expected value.
+ if(end_code.substr(_start_code.length(), end_code.length() - _start_code.length()) != expected_added_code)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ std::string _start_code{};
+};
+
+} // namespace ckw
+
+#endif // CKW_VALIDATION_TESTS_COMMON_KERNELWRITERINTERCEPTOR_H